Список работ

Программирование таблиц на JavaScript

Содержание

Введение

Программирование html-таблиц рассматривается на примере создания игры Пятнашки. Для этой игры нужна 4×4-таблица.
Приводимый далее код позволяет:

Также поддерживаются разные виды курсоров мыши (pointer, crosshair и default, [1]) и иной необходимый для игры функционал.

Создание html-таблицы

Приводимая ниже функция mkTbl создает n×n-таблицу с квадратными ячейками с n строками и с n столбцами. Функция принимает два параметра: размер ячейки и размер таблицы. Кроме того, в функции определяется обработчик sayRC события click ячейки таблицы, выводящий сообщение о координатах ячейки таблицы. Обработчик принимает ссылку на ячейку таблицы, принявшую мышиный удар.
В коде также присутствуют две глобальные переменные tbl и mT (соответственно ссылка на таблицу и размер таблицы), используемые в функциях создаваемой программы.

tbl = "";
mT = 0;
function mkTbl(tdSz, n) {
 mT = n;
 td = "<td style = 'background-color:#f0f0f0; width:" + tdSz + "; height:" + tdSz + "'";
 td += " onclick = 'sayRC(this)'></td>";
 tHdr = "<table id = 'tbl' style = 'background-color:#ccccaa; cursor:pointer'; border = 1px";
 document.write(tHdr);
 for (i = 0; i < mT; i++) {
  document.write("<tr>");
  for (j = 0; j < mT; j++) {
   document.write(td);
  }
  document.write("</tr>");
 }
 document.write("</table>");
 tbl = document.getElementById("tbl");
}
function sayRC(cll) {
 // Номер столбца текущей ячейки
 c = cll.cellIndex;
 r = gtRw(cll, c);
 alert("Ячейка " + r + ":" + c);
}
// Возвращает номер строки, которой расположена ячейка cll
function gtRw(cll, c) {
 for (i = 0; i < mT; i++) {
  rw = tbl.rows[i];
  if (rw.cells[c] == cll) return i;
 }
}

Замечание. В дальнейшем для придания курсору мыши надлежащего вида будет употреблен следующий код:

tbl.style.cursor = 'pointer' // Или иной вид, например crosshair

Запишем приведенный код в файл tryTbl.js и построим html-таблицу, открыв в обозревателе файл tst.html, имеющий следующее наполнение:

<!DOCTYPE HTML>
<html>
 <head>
  <meta http-equiv = "Content-Type" content = "text/html; charset=windows-1251">
  <title>Таблица на JavaScript</title>
  <script type = "text/javascript" src = "tryTbl.js"></script>
 </head>
 <body style = "background-color: rgb(240, 250, 250)">
  <script type = "text/javascript">
   mkTbl('50px', 5);
  </script>
 </body>
</html>

Оба файла (tryTbl.js и tst.html) находятся в одной папке.
Получаемый после открытия обозревателем файла tst.html результат можно наблюдать на рис. 1.

Html-таблица с курсором pointer

Рис. 1. Таблица с курсором pointer

После удара мышью по ячейке таблицы появится следующее сообщение (рис. 2):

Оповещение web-страницы

Рис. 2. Выбрана третья ячейка во второй строке таблицы (cellIndex = 2, rowIndex = 1)

Начальное заполнение таблицы

В игре Пятнашки все, кроме одной, ячейки таблицы изначально случайным образом заполняются цифрами от 1 до n×n - 1, где n - размер заполняемой таблицы.
Это действие можно выполнить при помощи следующего кода.

function nGmFftngs() {
 // mT - размер заполняемой таблицы
 fL = mT * mT;
 // Массив генерируемых целых чисел
 arrF = new Array(fL);
 // Массив флажков генерируемых целых чисел
 // Элемент arrF2[k] равен false, если число k уже имеется в массиве arrF
 arrF2 = new Array(fL);
 for (k = 0; k < fL; k ++) {
  arrF[k] = 0;
  arrF2[k] = true;
 }
 kL = kL2 = 0;
 // Цикл заполнения массива arrF
 // Число итераций не более 10000
 while (kL < fL && kL2++ < 10000) {
  // Получаем целое случайное число из диапазона [1, fL]
  k = Math.floor(Math.random() * (fL + 1));
  if (k > 0 && arrF2[k - 1]) {
   arrF2[k - 1] = false;
   arrF[kL] = k;
   kL++;
  }
 }
 kL = 0;
 // Цикл заполнения таблицы числами из массива arrF
 for (i = 0; i < mT; i++) {
  rw = tbl.rows[i];
  for (j = 0; j < mT; j++) {
   k = arrF[kL++];
   rw.cells[j].innerHTML = (k > fL - 1) ? "" : k;
  }
 }
}

Замечание. Взамен innerHTML можно употребить innerText

rw.cells[j].innerText = (k > fL - 1) ? "" : k;

Поместим этот код в уже имеющийся файл tryTbl.js. Пробный вызов функции обеспечит исполнение обозревателем модифицированного файла tst.html:

<!DOCTYPE HTML>
<html>
 <head>
  <meta http-equiv = "Content-Type" content = "text/html; charset=windows-1251">
  <title>Таблица на JavaScript</title>
  <style type = "text/css">
   td {
    text-indent: 0;
    text-align: center;
    font-weight: bold;
    font-size: 27px;
    color: black;
   }
  </style>
   <script type = "text/javascript" src = "tryTbl.js"></script>
 </head>
 <body style = "background-color: rgb(240, 250, 250)">
  <script type = "text/javascript">
   mkTbl('50px', 5);
   nGmFftngs();
  </script>
</body>
</html>

По сравнению с первоначальным вариантом в текущем варианте файла tst.html добавлены определение стиля текста ячейки таблицы и вызов функции nGmFftngs, заполняющей таблицу. Результат приведен на рис. 3.

Math.random-заполнение html-таблицы

Рис. 3. Случайное заполнение 5×5-таблицы

Управление формой курсора

Цифра, соседствующая с пустой ячейкой по горизонтали или вертикали, может быть перемещена в эту ячейку. Так, в ситуации, приведенной на рис. 3, в пустую ячейку можно переместить цифру 3, 11, 14 или 15.
В приводимой программе курсор мыши, если он расположен над цифрой соседом, имеет вид pointer, в противном случае курсор отображается как crosshair. Такое поведение обеспечивает обработчик mkCrsr события mouseover, возникающего при позиционировании мыши на ячейке таблицы.

Этот обработчик задается в модифицированной функции mkTbl создания таблицы. В этой функции строка кода

td += " onclick = 'sayRC(this)'></td>";

заменяется на следующую строку:

td += " onmouseover = 'mkCrsr(this)' onclick = 'sayRC(this)'></td>";

Сам же обработчик задается следующими функциями (обе функции помещены в файл tryTbl.js):

function mkCrsr(cll) {
 c = cll.cellIndex;
 r = gtRw(cll, c);
 if (r == -1)
  mvd = false;
 else
  for (kL = 0; kL < 4; kL++) {
   switch (kL) {
    case 0 : mvd = chkC2(r - 1, c, cll); break;
    case 1 : mvd = chkC2(r, c - 1, cll); break;
    case 2 : mvd = chkC2(r + 1, c, cll); break;
    case 3 : mvd = chkC2(r, c + 1, cll); break;
   }
   if (mvd) break;
  }
 tbl.style.cursor = (mvd) ? 'pointer' : 'crosshair';
}
// Возвращает true, если ячейка r2:c2 является пустой
function chkC2(r2, c2, cll) {
 if (r2 == -1 || c2 == -1 || r2 == mT || c2 == mT) return false;
 cll2 = tbl.rows[r2].cells[c2];
 if (cll2.innerHTML == "") return true;
}

Обе формы курсора можно наблюдать на рис. 4.

pointer и crosshair-курсоры

Рис. 4. Над цифрой 3 курсор имеет вид pointer, а над цифрой 2 - crosshair

Замечание. Курсор, если он расположен вне таблицы, имеет вид default.

Проверка обработчика выполняется в результате открытия файла tst.html.

Перемещение цифры

Цифра, соседствующая по горизонтали или вертикали с пустой ячейкой, занимает эту ячейку при помощи обработчика mvFg события click, возникающего после удара мышью по цифре. Освобождаемая ячейка становится пустой (рис. 5).

Курсор pointer над перемещаемой цифрой и crosshair над пустой ячейкой

Рис. 5. Перемещение цифры 7 обработчиком mvFg события click

Этот обработчик задается в модифицированной функции mkTbl создания таблицы. В этой функции строка кода

td += " onclick = 'sayRC(this)'></td>";

заменяется на следующую строку:

td += " onmouseover = 'mkCrsr(this)' onclick = 'mvFg(this)'></td>";

Обработчик реализуется следующими функциями (обе функции помещены в файл tryTbl.js):

function mvFg(cll) {
 c = cll.cellIndex;
 r = gtRw(cll, c);
 if (r == -1) return;
 fL = mT * mT;
 for (kL = 0; kL < 4; kL++) {
  switch (kL) {
   case 0 : mvd = chkC(r - 1, c, cll); break;
   case 1 : mvd = chkC(r, c - 1, cll); break;
   case 2 : mvd = chkC(r + 1, c, cll); break;
   case 3 : mvd = chkC(r, c + 1, cll); break;
  }
 }
}
function chkC(r2, c2, cll) {
 if (r2 == -1 || c2 == -1 || r2 == mT || c2 == mT) return false;
 cll2 = tbl.rows[r2].cells[c2];
 if (cll2.innerHTML == "") {
  cll2.innerHTML = cll.innerHTML;
  cll.innerHTML = "";
  tbl.style.cursor = 'crosshair';
  return true;
 }
}

Проверка обработчика выполняется в результате открытия файла tst.html.

Итоговый код

В итоговый JavaScript-код добавлены строки, обеспечивающие:

Итоговый JavaScript-код нужно поместить в файл fftngs.js.

// Глобальные переменные
tbl = "";
mT = 0;
dn = false;
tmS = 0;
nFftngs = 0;
//
function mkTbl(tdSz, n) {
 mT = n;
 td = "<td style = 'background-color:#f0f0f0; width:" + tdSz + "; height:" + tdSz + "'";
 td += " onmouseover = 'mkCrsr(this)' onclick = 'mvFg(this)'></td>";
 tHdr = "<table id = 'tbl' style = 'background-color:#ccccaa; cursor:pointer'; border = 1px";
 document.write(tHdr);
 for (i = 0; i < mT; i++) {
  document.write("<tr>");
  for (j = 0; j < mT; j++) {
   document.write(td);
  }
  document.write("</tr>");
 }
 document.write("</table>");
}
function sayRC(cll) {
 // Номер столбца текущей ячейки
 c = cll.cellIndex;
 r = gtRw(cll, c);
 alert("Ячейка " + r + ":" + c);
}
// Возвращает номер строки, которой расположена ячейка cll
function gtRw(cll, c) {
 for (i = 0; i < mT; i++) {
  rw = tbl.rows[i];
  if (rw.cells[c] == cll) return i;
 }
}
function nGmFftngs() {
 dn = false;
 nFftngs = 0;
 dt = new Date();
 tmS = dt.getTime();
 // mT - размер заполняемой таблицы
 fL = mT * mT;
 // Массив генерируемых целых чисел
 arrF = new Array(fL);
 // Массив флажков генерируемых целых чисел
 // Элемент arrF2[k] равен false, если число k уже имеется в массиве arrF
 arrF2 = new Array(fL);
 for (k = 0; k < fL; k ++) {
  arrF[k] = 0;
  arrF2[k] = true;
 }
 kL = kL2 = 0;
 // Цикл заполнения массива arrF
 // Число итераций не более 10000
 while (kL < fL && kL2++ < 10000) {
  // Получаем целое случайное число из диапазона [1, fL]
  k = Math.floor(Math.random() * (fL + 1));
  if (k > 0 && arrF2[k - 1]) {
   arrF2[k - 1] = false;
   arrF[kL] = k;
   kL++;
  }
 }
 kL = 0;
 // Цикл заполнения таблицы числами из массива arrF
 for (i = 0; i < mT; i++) {
  rw = tbl.rows[i];
  for (j = 0; j < mT; j++) {
   k = arrF[kL++];
   rw.cells[j].innerHTML = (k > fL - 1) ? "" : k;
  }
 }
}
function mkCrsr(cll) {
 if (dn) mvd = false;
 else {
  c = cll.cellIndex;
  r = gtRw(cll, c);
  if (r == -1)
   mvd = false;
  else
   for (kL = 0; kL < 4; kL++) {
    switch (kL) {
     case 0 : mvd = chkC2(r - 1, c, cll); break;
     case 1 : mvd = chkC2(r, c - 1, cll); break;
     case 2 : mvd = chkC2(r + 1, c, cll); break;
     case 3 : mvd = chkC2(r, c + 1, cll); break;
    }
    if (mvd) break;
   }
 }
 tbl.style.cursor = (mvd) ? 'pointer' : 'crosshair';
}
// Возвращает true, если ячейка r2:c2 является пустой
function chkC2(r2, c2, cll) {
 if (r2 == -1 || c2 == -1 || r2 == mT || c2 == mT) return false;
 cll2 = tbl.rows[r2].cells[c2];
 if (cll2.innerHTML == "") return true;
}
function mvFg(cll) {
 if (dn) return;
 c = cll.cellIndex;
 r = gtRw(cll, c);
 if (r == -1) return;
 fL = mT * mT;
 for (kL = 0; kL < 4; kL++) {
  switch (kL) {
   case 0 : mvd = chkC(r - 1, c, cll); break;
   case 1 : mvd = chkC(r, c - 1, cll); break;
   case 2 : mvd = chkC(r + 1, c, cll); break;
   case 3 : mvd = chkC(r, c + 1, cll); break;
  }
  // Проверяем, завершена игра или нет
  if (mvd) {
   // Переменная dn будет равна true, если игра завершена
   dn = true;
   k = 0;
   for (i = 0; i < mT; i++) {
    rw = tbl.rows[i];
    for (j = 0; j < mT; j++) {
     k++;
     if (k < fL && rw.cells[j].innerHTML != k) {
      dn = false;
      break;
     }
    }
    if (!dn) break;
   }
   if (dn) sRslt();
   break;
  }
 }
}
function chkC(r2, c2, cll) {
 if (r2 == -1 || c2 == -1 || r2 == mT || c2 == mT) return false;
 cll2 = tbl.rows[r2].cells[c2];
 if (cll2.innerHTML == "") {
  nFftngs++;
  cll2.innerHTML = cll.innerHTML;
  cll.innerHTML = "";
  tbl.style.cursor = 'crosshair';
  return true;
 }
}
// Выстраивает кости в надлежащем порядке
function bldFftngs() {
 if (dn) return;
 k = 0;
 for (i = 0; i < mT; i++) {
  rw = tbl.rows[i];
  for (j = 0; j < mT; j++) rw.cells[j].innerHTML = (++k > 15) ? "" : k;
 }
 dn = true;
 sRslt();
}
// Показывает потраченные время и число ходов
function sRslt() {
 dt = new Date();
 tm = Math.round(0.001 * (dt.getTime() - tmS));
 alert("Игра завершена. Число ходов " + nFftngs + ". Затрачено времени " + tm + " с.");
}

Переход к игре осуществляется в результате открытия файла fftngs.html, воспроизводящего описание игры (рис. 6), ее инициализацию и завершение.

Инициализация игры в обозревателе

Рис. 6. В обозревателе открыт файл fftngs.html

Файл fftngs.html содержит следующий код:

<!DOCTYPE HTML>
<html>
 <head>
  <meta http-equiv = "Content-Type" content = "text/html; charset=windows-1251">
  <title>Пятнашки</title>
  <style type = "text/css">
   td {
    text-indent: 0;
    text-align: center;
    font-weight: bold;
    font-size: 27px;
    color: black;
   }
   .dv {
    width: 400px;
    height: 300px;
    position: relative;
    top: 0;
    left: 0;
    background-color: white;
    float: left;
    margin-left: 6px;
    margin-right: 6px;
   }
   p {
    margin-top: 6px;
    margin-bottom: 6px;
    font-size: 12pt;
   }
   .btn {
    font-size: 14px;
    font-weight: 400;
    font-family: "Times New Roman", serif;
    width: 80px;
    height: 25px;
    margin-right: 4px;
   }
  </style>
  <script type = "text/javascript" src = "fftngs.js"></script>
 </head>
 <body>
  <div class = "dv">
   <p><b>Пятнашки</b></p>
   <p>Расположите числа в порядке возрастания,</p>
   <p>поместив первые 4 в первой строке таблицы,</p>
   <p>следующие 4 - во второй строке таблицы и так далее</p>
   <p>Для перемещение числа используйте мышиный удар.</p>
   <br>
   <p>
    <input type = "button" class = "btn" value = "Новая" onclick = "nGmFftngs()" title = "Начни сначала"> 
    <input type = "button" class = "btn" value = "Завершить" onclick = "bldFftngs()" title = "Получить решение"> 
   </p>
  </div>
  <script type = "text/javascript">
   mkTbl("50px", 4);
   tbl = document.getElementById("tbl");
   nGmFftngs();
  </script>
 </body>
</html>

После завершения игры функция sRslt обеспечит приведенное на рис. 7 сообщение.

Сообщение с web-страницы после завершения игры

Рис. 7. Игра окончена

Замечание. Игру Пятнашки можно опробовать на странице сайта 100byte.ru.

Заключение

Html-таблица является достаточно сложным объектом. В частности, ее ячейка (HTMLElement td) имеет следующие события, методы и свойства (их детальное описание можно найти в [2]):

Столь же емки и иные определяемые в таблице объекты: table, tr, th и др.

Источники

  1. http://htmlbook.ru/css/cursor.
  2. http://msdn.microsoft.com/en-us/library/ie/ms535903(v=vs.85).aspx.

Список работ

Рейтинг@Mail.ru