Игра «Пятнашки» на JavaScript

Пятнашки — простая и многим с детства знакомая головоломка, поэтому я не буду рассказывать про правила, надеюсь, они вам знакомы. Во многих учебниках по программированию предлагается в качестве урока написать эту головоломку. Напишем и мы её на JavaScript. Верстать тут много не придётся, html-код короток и банален:

1
2
3
4
5
6
7
8
9
10
<html>
	<head>
		<title>Пятнашки</title>
		<script type="text/javascript" src="15.js"></script>
	</head>
	<body>
		<div id="box"></div>
           		<button id="reset">New Game<button>
	</body>
</html>

В

<div id="box"></div>

будет располагаться игровое поле. JavaScript код расположим в файле 15.js. Для хранения номеров костяшек будем использовать ступенчатый массив, то есть массив массивов. Забьём его по порядку числами от одного до пятнадцати, а значение последнего элемента установим равным пустой строке. Этому элементу будет соответствовать место не занятое костяшкой. Создадим функцию newGame и в её тело запишем:

1
2
3
4
5
6
7
8
9
10
var arr = [];
for(i = 0; i &lt; 4; ++i){
		arr[i] = [];
		for(j = 0; j &lt; 4; ++j){
			if(i + j != 6)
				arr[i][j] = i*4 + j + 1;
			else
				arr[i][j] = "";
		}
	}

Такое расположение элементов в массиве соответствует выигрышному расположению костяшек.

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

1
2
3
4
5
function swap(arr,i1,j1,i2,j2){				
t = arr[i1][j1];
	arr[i1][j1] = arr[i2][j2];
	arr[i2][j2] = t;
}

Теперь напишем код, который будет отвечать за перемешивание. Этот код тоже расположим в функции newGame. Её мы будем вызывать, как только страничка будет загружена, или когда пользователь кликнет по кнопке “New game”.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
ei = 3;//Запоминаем индексы элемента массива,
ej = 3;// в котором записана пустая строка.
for(i = 0; i &lt; 2012; ++i) // На мой взгляд 2012 это достаточно много =)
		// Случайным образом выбираем число от 0 до 3
		switch(Math.round(3*Math.random())){
	/*
	 * 0 соответсвует верхней соседней костяшке, 1 - правой  и т.д.
	 * обратим внимание что обмен местами, например,
	 * с верхней костяшкой возможен, если "пустое место"
	 * не ноходится у верхней границы игрового поля. Аналогично и для
	 * других соседних костяшек. При обмене изменяем переменные ei и ej.
	 */						
			case 0: if(ei != 0) swap(arr,ei,ej,--ei,ej); break; 
			case 1: if(ej != 3) swap(arr,ei,ej,ei, ++ej); break; 
			case 2: if(ei != 3) swap(arr,ei,ej,++ei,ej); break; 
			case 3: if(ej != 0) swap(arr,ei,ej,ei,--ej); 
		}

Забить массив arr случайными неповторяющимися цифрами от 0 до 15 нельзя, поскольку не любое расположение костяшек можно привести к собранной комбинации. Теперь пишем код, с помощью которого мы сформируем таблицу, в ячейках которой будут располагаться уже перемешанные элементы массива arr. Этот код так же будет располагаться в функции newGame.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
var table = document.createElement("table"); //Cоздаём таблицу	
for(i = 0; i &lt; 4; ++i){
var row = document.createElement("tr"); //Добавляем в неё строки
		for(j = 0; j &lt; 4; ++j){
			var cell = document.createElement("td");//Cоздаём ячейки
			cell.id = i + " " + j;
/*
			 * Привязываем к событию, происходящему
			 * при клике по ячейке таблицы функцию
			 * cellClick 
			 */
			cell.onclick = cellClick;
//Записываем в ячейку соответсвующий эл-т массива
			cell.innerHTML = arr[i][j];
row.appendChild(cell);// Добавляем ячейку в строку
		}
	table.appendChild(row);// Добавляем строку в итаблицу			
}
/*
	 * Проверяем, нет ли у
 
<div id="box"> дочернего эл-та.
	 * То есть таблицы. Она уже будет на странице
	 * если  функция newGame вызвана нажатием
	 * кнопки "New game", а не при загрузки страницы.
*/
if(box.childNodes.length == 1) 
box.removeChild(box.firstChild); //Удаляем таблицу, если она есть	
box.appendChild(table);// Запихиваем в box table</div>

При клике на ячейку таблицы необходимо менять её местами с пустой ячейкой, если она соседняя. Мы уже привязали функцию cellClick к событию, происходящему при клике по ячейке таблицы. Теперь напишем код этой функции.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
function cellClick(e){				
var el = e.srcElement || e.target;
	/*
	 * получаем номер строки и столбца, на пересечении которых
	 * расположена ячейка. Мы записали их ранее в её id ячейки.
	 */
	var i = el.id.charAt(0),
	j = el.id.charAt(2);
	/*
	 * Если пустая ячейка расположена в одном стобце или строке
	 * с ячейкой, по которой кликнули, и расстояние между
	 * этими ячейками 1, то меняем их содержимое местами
	 */
if((i == ei &amp;&amp; Math.abs(j - ej) == 1) || (j == ej &amp;&amp; Math.abs(i - ei) == 1)){
document.getElementById(ei + " " + ej).innerHTML = el.innerHTML;
	el.innerHTML = "";
	//Запоминаем положение пустой ячейки
	ei = i;
	ej = j;
	var q = true;
	//Проверяем не в выигрышной ли комбинации находятся ячейки.
	for(i = 0; i &lt; 4; ++i)
		for(j = 0; j &lt; 4; ++j)
			if(i + j != 6 &amp;&amp; document.getElementById(i + " " + j).innerHTML != i*4 + j + 1){
				q = false;
				break;
		}
	if(q) alert("Victory!");
	}
}

При загрузке страницы вызываем функцию newGame, в которой мы перемешиваем элементы массива arr, добавляем на страницу игровое поле, записываем в переменную box — div, в который мы, в последствии, запихнём игровое поле.

1
2
3
4
5
window.onload = function() {
		box = document.getElementById("box");
			newGame();				
			document.getElementById("reset").onclick = newGame;
}

Осталось только всё это оформить по вкусу и готово!

Демо | Исходники