See the source code below.
You can play with it here : SlidingPuzzle;
The code is not yet documented. If you are interested, I will be glad to answer your questions...
<html lang="de">
<head>
<meta charset="utf-8">
<title>title</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://efpage.de/DML/DML_homepage/lib/DML-min.js"></script>
</head>
<body>
<script>
function sleep (ms) {
return new Promise((r,err) => {
setTimeout(r,ms)
})
}
class Board {
cssCell = `
background:blueviolet;height:100px; width:100px;
margin:2px;cursor:pointer;flex: 0 0 100px;
display:flex;align-items: center;
justify-content: center;color: orange;
`
cssBoard = `
padding:5px;display:flex;
flex-wrap:wrap;background:orange;
width:416px;margin:0 auto;
`
checkValidBoard () {
function checkPos (c) {
return c.dataset.pos == c.dataset.curpos
}
return this.cells.every(checkPos);
}
findDirectionToMove(cell) {
const [getCol,getRow] = [(pos) => pos%4,(pos) => Math.trunc(pos/4)]
const cellpos = Number(cell.dataset.curpos);
const emptyCellpos = Number(this.emptyCell.dataset.curpos);
const rowcolEmpty = [getRow(emptyCellpos), getCol(emptyCellpos)];
const rowcolCell = [getRow(cellpos), getCol(cellpos)];
const sameColOrRow =
(rowcolEmpty[0] == rowcolCell[0] ) || (rowcolEmpty[1] == rowcolCell[1]);
if (!sameColOrRow) return;
const directions = {
[ cellpos - 1] : "left",
[ cellpos + 1] : "right",
[ cellpos - 4] : "up",
[ cellpos + 4] : "down"
}
let posdir = Object.keys(directions).find(pos => pos == emptyCellpos);
return (directions[posdir]);
}
findOpositeDirection(direction) {
if (direction == "up") { return "down" }
if (direction == "down") { return "up" }
if (direction == "left") { return "right" }
if (direction = "right") { return "left" }
}
moveCell (cell) {
const direction = this.findDirectionToMove(cell);
if (!direction) return;
const amount = 104;
const duration = 200;
const coef = {
'left' : -1,
'right' : 1,
'down' : 1,
'up' : -1
}
const oppositeDirection = this.findOpositeDirection(direction);
const cssTranslate = (cell, direction) => {
if (direction == 'left' || direction == 'right') {
cell.dataset.dx = Number(cell.dataset.dx) + amount * coef[direction]
}
if (direction == 'up' || direction == 'down') {
cell.dataset.dy = Number(cell.dataset.dy) + amount * coef[direction]
}
return `translate(${cell.dataset.dx}px, ${cell.dataset.dy}px )`
}
cell.animate(
{transform: cssTranslate(cell, direction)},
{duration: duration, fill: "forwards"});
this.emptyCell.animate(
{transform: cssTranslate(this.emptyCell, oppositeDirection)},
{duration: duration, fill: "forwards"}
);
let temp = this.emptyCell.dataset.curpos;
this.emptyCell.dataset.curpos = cell.dataset.curpos;
cell.dataset.curpos = temp;
if (cell.dataset.pos != cell.dataset.curpos) {
cell.style.background = "deeppink";
cell.style.color = "white";
}
else {
cell.style.background = "blueviolet";
}
}
createCells () {
// fills cells array with cell element
this.cells = [...Array(16)].map((_, i) => {
let options = {
style : this.cssCell,
["data-pos"] : i, ["data-curpos"] : i,
["data-dx"] : 0, ["data-dy"] : 0
}
let content = h1(`${i}`);
let cell = create("div", options, content);
cell.onclick = () => this.moveCell(cell);
return cell;
});
// empty cell customisation
this.emptyCell = this.cells[15];
this.emptyCell.style.background = "rgba(255,0,0,0.0)";
this.emptyCell.style.zIndex = 0;
this.emptyCell.style.color = "transparent";
}
displayBoard () {
selectBase(div(""));
print("<h1 style='text-align:center'>Sliding Puzzle</h1>");
unselectBase();
selectBase(div("", {style: this.cssBoard}));
this.cells.map(appendBase);
unselectBase();
selectBase(div("", "text-align:center;margin-top:20px"));
button("Shuffle") .onclick = () => this.shuffle();
unselectBase();
}
moveCellByCurpos(cellpos) {
let cell = this.cells.find(cell => cell.dataset.curpos == cellpos);
this.moveCell(cell);
}
async shuffle () {
for (let i = 0; i < 200; i++) {
const emptyPos = Number(this.emptyCell.dataset.curpos);
const validPos = [
emptyPos - 1, emptyPos + 1,
emptyPos - 4, emptyPos + 4
].filter(pos => {return (pos >= 0) && (pos <= 15);
})
const randomPos= validPos[Math.floor(Math.random()*validPos.length)];
await sleep(90);
this.moveCellByCurpos(randomPos);
}
}
start () {
this.createCells ();
this.displayBoard();
}
}
function main() {
let b = new Board();
b.start()
}
main();
</script>
</body>
</html>
Top comments (0)