15 puzzle
"15 puzzle" — скрипт на JavaScript, разрабатываемый в рамках лаборатории создания сайтов как учебный (не обучающий) проект.
Цель: разработать скрипт на JavaScript (с применением HTML), реализующий функциональность игры Пятнашки.
Примечание: Это мой первый скрипт, поэтому прошу не причислять скрипт к индусскому коду или говнокоду. Исходный код сохраняется с целью показать, какие ошибки допускают начинающие программисты, как их исправить и не допускать в дальнейшем.
Содержание |
[править] Разработка
[править] Этап 1
Создадим файл 15puzzle.html. Этот файл будет содержать и HTML-представление и сам скрипт.
- Ошибка: Нужно разделять логику и представление, используя отдельно код HTML, CSS и JavaScript. Для исправления ошибки нужно создать также файлы 15puzzle.css и 15puzzle.js.
[править] Этап 2
Сначала создадим простейшее визуальное представление квадратной коробки и блоков (как на рисунке 1). Здесь будем использовать элементы table, tr, td.
Исходный код:
<table> <tr><td>1</td><td>2</td><td>3</td><td>4</td> </tr> <tr> <td>5</td><td>6</td><td>7</td><td>8</td> </tr> <tr> <td>9</td><td>10</td><td>11</td><td>12</td> </tr> <tr> <td>13</td><td>14</td><td>15</td><td> </td> </tr> </table>
Представление:
| 1 | 2 | 3 | 4 |
| 5 | 6 | 7 | 8 |
| 9 | 10 | 11 | 12 |
| 13 | 14 | 15 |
- Ошибка: Нужно соблюдать стандарты кодирования HTML. Для исправления ошибки вставим информацию о версии HTML (!DOCTYPE) и шапку веб-страницы. Теорию смотрите в HTML/§1. Введение и в HTML/§2. Структура веб-страницы.
[править] Этап 3
Теперь добавим в тег table дополнительные атрибуты: align, bgcolor, border, bordercolor, height, width.
Исходный код:
<table align="center" bgcolor="#FAEBD7" border="9" bordercolor="#DEB887" height="300px" width="300px"> <tr><td>1</td><td>2</td><td>3</td><td>4</td> </tr> <tr> <td>5</td><td>6</td><td>7</td><td>8</td> </tr> <tr> <td>9</td><td>10</td><td>11</td><td>12</td> </tr> <tr> <td>13</td><td>14</td><td>15</td><td> </td> </tr> </table>
[править] Этап 4
Теперь добавим в теги tr дополнительные атрибуты: align, bgcolor.
Исходный код:
<table align="center" bgcolor="#FAEBD7" border="9" bordercolor="#DEB887" height="300px" width="300px"> <tr align="center" bgcolor="#F0F8FF"> <td>1</td><td>2</td><td>3</td><td>4</td> </tr> <tr align="center" bgcolor="#F0F8FF"> <td>5</td><td>6</td><td>7</td><td>8</td> </tr> <tr align="center" bgcolor="#F0F8FF"> <td>9</td><td>10</td><td>11</td><td>12</td> </tr> <tr align="center" bgcolor="#F0F8FF"> <td>13</td><td>14</td><td>15</td><td> </td> </tr> </table>
[править] Этап 5
Как видим, нам нужно сделать цвет каждой ячейки по-отдельности, чтобы цвет пустой ячейки был отличный от цвета блоков. Добавим в теги td дополнительный атрибут bgcolor, а из тегов tr удаляем этот атрибут.
Исходный код:
<table align="center" bgcolor="#FAEBD7" border="9" bordercolor="#DEB887" height="300px" width="300px"> <tr align="center"> <td bgcolor="#F0F8FF">1</td><td bgcolor="#F0F8FF">2</td><td bgcolor="#F0F8FF">3</td><td bgcolor="#F0F8FF">4</td> </tr> <tr align="center"> <td bgcolor="#F0F8FF">5</td><td bgcolor="#F0F8FF">6</td><td bgcolor="#F0F8FF">7</td><td bgcolor="#F0F8FF">8</td> </tr> <tr align="center"> <td bgcolor="#F0F8FF">9</td><td bgcolor="#F0F8FF">10</td><td bgcolor="#F0F8FF">11</td><td bgcolor="#F0F8FF">12</td> </tr> <tr align="center"> <td bgcolor="#F0F8FF">13</td><td bgcolor="#F0F8FF">14</td><td bgcolor="#F0F8FF">15</td><td> </td> </tr> </table>
[править] Этап 6
Теперь заполним блоки числами в случайном порядке, используя функции document.write(), Math.floor() и Math.random().
Исходный код:
<script> var a1 = Math.floor(Math.random()*15 + 1); var a2 = Math.floor(Math.random()*15 + 1); var a3 = Math.floor(Math.random()*15 + 1); var a4 = Math.floor(Math.random()*15 + 1); var a5 = Math.floor(Math.random()*15 + 1); var a6 = Math.floor(Math.random()*15 + 1); var a7 = Math.floor(Math.random()*15 + 1); var a8 = Math.floor(Math.random()*15 + 1); var a9 = Math.floor(Math.random()*15 + 1); var a10 = Math.floor(Math.random()*15 + 1); var a11 = Math.floor(Math.random()*15 + 1); var a12 = Math.floor(Math.random()*15 + 1); var a13 = Math.floor(Math.random()*15 + 1); var a14 = Math.floor(Math.random()*15 + 1); var a15 = Math.floor(Math.random()*15 + 1); </script>
<table align="center" bgcolor="#FAEBD7" border="9" bordercolor="#DEB887" height="300px" width="300px"> <tr align="center"> <td bgcolor="#F0F8FF"><script>document.write(a1);</script></td><td bgcolor="#F0F8FF"><script>document.write(a2);</script></td> <td bgcolor="#F0F8FF"><script>document.write(a3);</script></td><td bgcolor="#F0F8FF"><script>document.write(a4);</script></td> </tr> <tr align="center"> <td bgcolor="#F0F8FF"><script>document.write(a5);</script></td><td bgcolor="#F0F8FF"><script>document.write(a6);</script></td> <td bgcolor="#F0F8FF"><script>document.write(a7);</script></td><td bgcolor="#F0F8FF"><script>document.write(a8);</script></td> </tr> <tr align="center"> <td bgcolor="#F0F8FF"><script>document.write(a9);</script></td><td bgcolor="#F0F8FF"><script>document.write(a10);</script></td> <td bgcolor="#F0F8FF"><script>document.write(a11);</script></td><td bgcolor="#F0F8FF"><script>document.write(a12);</script></td> </tr> <tr align="center"> <td bgcolor="#F0F8FF"><script>document.write(a13);</script></td><td bgcolor="#F0F8FF"><script>document.write(a14);</script></td> <td bgcolor="#F0F8FF"><script>document.write(a15);</script></td><td> </td> </tr> </table>
[править] Этап 7
Как видно из рисунка 6, исказились размеры блоков. Для исправления этих размеров добавим в теги td первого ряда блоков тег width.
Исходный код:
<script> var a1 = Math.floor(Math.random()*15 + 1); var a2 = Math.floor(Math.random()*15 + 1); var a3 = Math.floor(Math.random()*15 + 1); var a4 = Math.floor(Math.random()*15 + 1); var a5 = Math.floor(Math.random()*15 + 1); var a6 = Math.floor(Math.random()*15 + 1); var a7 = Math.floor(Math.random()*15 + 1); var a8 = Math.floor(Math.random()*15 + 1); var a9 = Math.floor(Math.random()*15 + 1); var a10 = Math.floor(Math.random()*15 + 1); var a11 = Math.floor(Math.random()*15 + 1); var a12 = Math.floor(Math.random()*15 + 1); var a13 = Math.floor(Math.random()*15 + 1); var a14 = Math.floor(Math.random()*15 + 1); var a15 = Math.floor(Math.random()*15 + 1); </script>
<table align="center" bgcolor="#FAEBD7" border="9" bordercolor="#DEB887" height="320px" width="320px"> <tr align="center"> <td bgcolor="#F0F8FF" width="80px"><script>document.write(a1);</script></td> <td bgcolor="#F0F8FF" width="80px"><script>document.write(a2);</script></td> <td bgcolor="#F0F8FF" width="80px"><script>document.write(a3);</script></td> <td bgcolor="#F0F8FF" width="80px"><script>document.write(a4);</script></td> </tr> <tr align="center"> <td bgcolor="#F0F8FF"><script>document.write(a5);</script></td><td bgcolor="#F0F8FF"><script>document.write(a6);</script></td> <td bgcolor="#F0F8FF"><script>document.write(a7);</script></td><td bgcolor="#F0F8FF"><script>document.write(a8);</script></td> </tr> <tr align="center"> <td bgcolor="#F0F8FF"><script>document.write(a9);</script></td><td bgcolor="#F0F8FF"><script>document.write(a10);</script></td> <td bgcolor="#F0F8FF"><script>document.write(a11);</script></td><td bgcolor="#F0F8FF"><script>document.write(a12);</script></td> </tr> <tr align="center"> <td bgcolor="#F0F8FF"><script>document.write(a13);</script></td><td bgcolor="#F0F8FF"><script>document.write(a14);</script></td> <td bgcolor="#F0F8FF"><script>document.write(a15);</script></td><td> </td> </tr> </table>
[править] Этап 8
Как видно из рисунка 7, совпадают числа некоторых блоков. Напишем функцию mismatch(), устраняющую эту проблему.
Исходный код:
<script> var a1 = Math.floor(Math.random()*15 + 1); var a2 = Math.floor(Math.random()*15 + 1); mismatch(2); var a3 = Math.floor(Math.random()*15 + 1); mismatch(3); var a4 = Math.floor(Math.random()*15 + 1); mismatch(4); var a5 = Math.floor(Math.random()*15 + 1); mismatch(5); var a6 = Math.floor(Math.random()*15 + 1); mismatch(6); var a7 = Math.floor(Math.random()*15 + 1); mismatch(7); var a8 = Math.floor(Math.random()*15 + 1); mismatch(8); var a9 = Math.floor(Math.random()*15 + 1); mismatch(9); var a10 = Math.floor(Math.random()*15 + 1); mismatch(10); var a11 = Math.floor(Math.random()*15 + 1); mismatch(11); var a12 = Math.floor(Math.random()*15 + 1); mismatch(12); var a13 = Math.floor(Math.random()*15 + 1); mismatch(13); var a14 = Math.floor(Math.random()*15 + 1); mismatch(14); var a15 = Math.floor(Math.random()*15 + 1); mismatch(15); function mismatch(n){ for (var i=1;i<n;i++){ if(window['a'+n]==window['a'+i]){ window['a'+n]=Math.floor(Math.random()*15 + 1); i=0; } } } </script>
<table align="center" bgcolor="#FAEBD7" border="9" bordercolor="#DEB887" height="320px" width="320px"> <tr align="center"> <td bgcolor="#F0F8FF" width="80px"><script>document.write(a1);</script></td> <td bgcolor="#F0F8FF" width="80px"><script>document.write(a2);</script></td> <td bgcolor="#F0F8FF" width="80px"><script>document.write(a3);</script></td> <td bgcolor="#F0F8FF" width="80px"><script>document.write(a4);</script></td> </tr> <tr align="center"> <td bgcolor="#F0F8FF"><script>document.write(a5);</script></td><td bgcolor="#F0F8FF"><script>document.write(a6);</script></td> <td bgcolor="#F0F8FF"><script>document.write(a7);</script></td><td bgcolor="#F0F8FF"><script>document.write(a8);</script></td> </tr> <tr align="center"> <td bgcolor="#F0F8FF"><script>document.write(a9);</script></td><td bgcolor="#F0F8FF"><script>document.write(a10);</script></td> <td bgcolor="#F0F8FF"><script>document.write(a11);</script></td><td bgcolor="#F0F8FF"><script>document.write(a12);</script></td> </tr> <tr align="center"> <td bgcolor="#F0F8FF"><script>document.write(a13);</script></td><td bgcolor="#F0F8FF"><script>document.write(a14);</script></td> <td bgcolor="#F0F8FF"><script>document.write(a15);</script></td><td> </td> </tr> </table>
[править] Этап 9
Добавим функции перемещения блоков an(), ap() и используем их с помощью события onClick. Теперь скрипт работоспособен и уже можно играть.
Исходный код:
<script> var a1 = Math.floor(Math.random()*15 + 1); var a2 = Math.floor(Math.random()*15 + 1); mismatch(2); var a3 = Math.floor(Math.random()*15 + 1); mismatch(3); var a4 = Math.floor(Math.random()*15 + 1); mismatch(4); var a5 = Math.floor(Math.random()*15 + 1); mismatch(5); var a6 = Math.floor(Math.random()*15 + 1); mismatch(6); var a7 = Math.floor(Math.random()*15 + 1); mismatch(7); var a8 = Math.floor(Math.random()*15 + 1); mismatch(8); var a9 = Math.floor(Math.random()*15 + 1); mismatch(9); var a10 = Math.floor(Math.random()*15 + 1); mismatch(10); var a11 = Math.floor(Math.random()*15 + 1); mismatch(11); var a12 = Math.floor(Math.random()*15 + 1); mismatch(12); var a13 = Math.floor(Math.random()*15 + 1); mismatch(13); var a14 = Math.floor(Math.random()*15 + 1); mismatch(14); var a15 = Math.floor(Math.random()*15 + 1); mismatch(15); var a16 = ' '; function mismatch(n){ for (var i=1;i<n;i++){ if(window['a'+n]==window['a'+i]){ window['a'+n]=Math.floor(Math.random()*15 + 1); i=0; } } } var a; var b; var с = ' '; function an(){ document.getElementById('td'+b).innerHTML=window["a"+a];document.getElementById('td'+b).style.background = '#F0F8FF'; window["a"+b]=window["a"+a]; } function ap(){ document.getElementById('td'+a).innerHTML=с;document.getElementById('td'+a).style.background = '#FAEBD7'; window["a"+a]=с } </script>
<table align="center" bgcolor="#FAEBD7" border="9" bordercolor="#DEB887" height="320px" width="320px"> <tr align="center"> <td bgcolor="#F0F8FF" width="80px" id="td1" onclick="if(window['a5']==с){a=1;b=5;an();ap();}if(window['a2']==с){a=1;b=2;an();ap();}"> <script>document.write(a1);</script></td> <td bgcolor="#F0F8FF" width="80px" id="td2" onclick="if(window['a1']==с){a=2;b=1;an();ap();}if(window['a6']==с){a=2;b=6;an();ap();} if(window['a3']==с){a=2;b=3;an();ap();}"> <script>document.write(a2);</script></td> <td bgcolor="#F0F8FF" width="80px" id="td3" onclick="if(window['a2']==с){a=3;b=2;an();ap();}if(window['a4']==с){a=3;b=4;an();ap();} if(window['a7']==с){a=3;b=7;an();ap();}"> <script>document.write(a3);</script></td> <td bgcolor="#F0F8FF" width="80px" id="td4" onclick="if(window['a3']==с){a=4;b=3;an();ap();}if(window['a8']==с){a=4;b=8;an();ap();}"> <script>document.write(a4);</script></td> </tr> <tr align="center"> <td bgcolor="#F0F8FF" id="td5" onclick="if(window['a1']==с){a=5;b=1;an();ap();}if(window['a6']==с){a=5;b=6;an();ap();} if(window['a9']==с){a=5;b=9;an();ap();}"> <script>document.write(a5);</script></td> <td bgcolor="#F0F8FF" id="td6" onclick="if(window['a2']==с){a=6;b=2;an();ap();}if(window['a5']==с){a=6;b=5;an();ap();} if(window['a7']==с){a=6;b=7;an();ap();}if(window['a10']==с){a=6;b=10;an();ap();}"> <script>document.write(a6);</script></td> <td bgcolor="#F0F8FF" id="td7" onclick="if(window['a3']==с){a=7;b=3;an();ap();}if(window['a6']==с){a=7;b=6;an();ap();} if(window['a8']==с){a=7;b=8;an();ap();}if(window['a11']==с){a=7;b=11;an();ap();}"> <script>document.write(a7);</script></td> <td bgcolor="#F0F8FF" id="td8" onclick="if(window['a4']==с){a=8;b=4;an();ap();}if(window['a7']==с){a=8;b=7;an();ap();} if(window['a12']==с){a=8;b=12;an();ap();}"> <script>document.write(a8);</script></td> </tr> <tr align="center"> <td bgcolor="#F0F8FF" id="td9" onclick="if(window['a5']==с){a=9;b=5;an();ap();}if(window['a10']==с){a=9;b=10;an();ap();} if(window['a13']==с){a=9;b=13;an();ap();}"> <script>document.write(a9);</script></td> <td bgcolor="#F0F8FF" id="td10" onclick="if(window['a6']==с){a=10;b=6;an();ap();}if(window['a9']==с){a=10;b=9;an();ap();} if(window['a11']==с){a=10;b=11;an();ap();}if(window['a14']==с){a=10;b=14;an();ap();}"> <script>document.write(a10);</script></td> <td bgcolor="#F0F8FF" id="td11" onclick="if(window['a7']==с){a=11;b=7;an();ap();}if(window['a10']==с){a=11;b=10;an();ap();} if(window['a12']==с){a=11;b=12;an();ap();}if(window['a15']==с){a=11;b=15;an();ap();}"> <script>document.write(a11);</script></td> <td bgcolor="#F0F8FF" id="td12" onclick="if(window['a8']==с){a=12;b=8;an();ap();}if(window['a11']==с){a=12;b=11;an();ap();} if(window['a16']==с){a=12;b=16;an();ap();}"> <script>document.write(a12);</script></td> </tr> <tr align="center"> <td bgcolor="#F0F8FF" id="td13" onclick="if(window['a9']==с){a=13;b=9;an();ap();}if(window['a14']==с){a=13;b=14;an();ap();}"> <script>document.write(a13);</script></td> <td bgcolor="#F0F8FF" id="td14" onclick="if(window['a10']==с){a=14;b=10;an();ap();}if(window['a13']==с){a=14;b=13;an();ap();} if(window['a15']==с){a=14;b=15;an();ap();}"> <script>document.write(a14);</script></td> <td bgcolor="#F0F8FF" id="td15" onclick="if(window['a11']==с){a=15;b=11;an();ap();}if(window['a14']==с){a=15;b=14;an();ap();} if(window['a16']==с){a=15;b=16;an();ap();}"> <script>document.write(a15);</script></td> <td bgcolor="#FAEBD7" id="td16" onclick="if(window['a12']==с){a=16;b=12;an();ap();}if(window['a15']==с){a=16;b=15;an();ap();}"></td> </tr> </table>
[править] Тестирование
Скрипт работает в браузерах Mozilla Firefox 3.6.10 и Internet Explorer 8 версии.
[править] Результаты
- Разработана игра-скрипт "15 puzzle" версия 0.1 (исходный код здесь). Размер исходного кода — 5 100 байт.
- Проект на Sourceforge
- Демо скрипта
- Код представлен к обсуждению на форуме Javascript.RU, где были получены полезные замечания и советы по исправлению и улучшению скрипта:
-
- Соблюдать стандарты кодирования,
- Использовать CSS,
- Разделять логику и представление,
- Не использовать document.write без необходимости,
- Использовать методы DOM,
- Создать массив из 15 элементов и перемешать их,
- Включить защиту от неразрешимых комбинаций.