JSFiddle - React, Tailwind, and code Playground
CSS
div {
margin-top: 20px;
width: 456px;
border: solid 1px transparent;
}
div > div {
display: inline-block;
width: 100px;
height: 100px;
border: solid 2px gray;
margin: 5px;
text-align: center;
font: bold 24px/100px Tahoma,sans;
border-radius: 10px;
background-color: whitesmoke;
}
JavaScript
let box = document.body.appendChild(document.createElement('div'));
let fifteen = {
// задаем слагаемое для вычисления нового индекса перемещаемого элемента
Move: { up: -4, left: -1, down: 4, right: 1 },
// индекс пустого элемента
hole: 15,
// задаем массив элементов пятнашек, сортируем случайным образом, добавляем 0 (пустая клетка)
order: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
.sort(() => Math.random()-0.5)
.concat(0),
// проверка на завершенность комбинации
// пробуем найти хоть один элемент, индекс которого(+1) не совпадает с его значением
// если есть хоть один элемент, стоящий не на месте, то комбинация не решена
// иначе пятнашки собраны
isCompleted() {
return !this.order.some((item, i) => item > 0 && item-1 !== i);
},
go(move) {
let index = this.hole + move;
if (!this.order[index]) {
return false;
}
if (move == fifteen.Move.left || move == fifteen.Move.right) {
if (Math.floor(this.hole/4) !== Math.floor(index/4)) {
return false;
}
}
this.swap(index, this.hole);
this.hole = index;
return true;
},
// меняем местами элементы с индексами i1 и i2
swap(i1, i2) {
let t = this.order[i1];
this.order[i1] = this.order[i2];
this.order[i2] = t;
},
// проверка расклада пятнашек в массиве а на решаемость
// считаем количество пар чисел, в которых предыдущее число больше последующего
// это Параметр беспорядка, если он четный - комбинация решаема
solvable(a) {
let kDiff = 0;
let len = a.length-1;
for (let i = 1; i < len; i++) {
for (let j = i-1; j >= 0; j--) {
if (a[j] > a[i]) {
kDiff++;
}
}
}
return !(kDiff % 2);
}
};
// если комбинация не решаема меняем местами первый и второй элементы
// таким образом параметр беспорядка изменится на 1 и станет четным
if (!fifteen.solvable(fifteen.order)) {
fifteen.swap(0, 1);
}
// добавляем на страницу 16 блоков
for (var i = 0;...