<div class="container">
</div>
HTML
格式化
支持Emmet,输入 p 后按 Tab键试试吧!
<head> ... </head>
<body>
</body>
body {
width: 100vw;
height: 100vh;
margin: 0;
padding: 0;
display: grid;
place-items: center;
}
.container {
display: grid;
grid-template-columns: repeat(10, 1fr);
grid-template-rows: repeat(10, 1fr);
column-gap: 5px;
row-gap: 5px;
}
.container>div {
width: 40px;
height: 40px;
border-radius: 2px;
transition: 0.25s all linear;
transform: translateX(0);
}
@for $i from 1 through 100 {
.container>div:nth-child(#{$i}) {
background-color: hsla(255/100 * $i, 90, 50, 1);
}
}
const gridLength = 10;
let emptyBoxIndex = gridLength * gridLength - 1;
let pIndex = -1;
const boxes = [];
const boxesMap = {};
const pos = [];
const speed = 300; // 速度调整,数值越小速度越快
const size = 40;
const gap = 5;
for (let x = 0; x < gridLength * gridLength - 1; x++) {
const div = document.createElement("div");
document.querySelector(".container").appendChild(div);
boxes.push(div);
boxesMap[x] = x;
pos.push([0, 0]);
}
boxesMap[gridLength * gridLength] = null;
pos.push([0, 0]);
const move = (index, pos) => {
boxes[index].style.transform = `translateX(${
pos[0] * (size + gap)
}px) translateY(${pos[1] * (size + gap)}px)`;
};
let start;
let steps = 0;
let accumulator = 0;
const walk = (timestamp) => {
if (start === undefined) start = timestamp;
accumulator += timestamp - start;
if (accumulator > speed) {
accumulator = 0;
steps++;
start = timestamp;
// generate a lut?
const adjacent = [];
if (
emptyBoxIndex > gridLength - 1 &&
emptyBoxIndex - gridLength !== pIndex
) {
// 不是第一行
adjacent.push(emptyBoxIndex - gridLength);
}
if (
emptyBoxIndex < gridLength * gridLength - gridLength &&
emptyBoxIndex + gridLength !== pIndex
) {
// 不是最后一行
adjacent.push(emptyBoxIndex + gridLength);
}
if (emptyBoxIndex % gridLength !== 0 && emptyBoxIndex - 1 !== pIndex) {
// 不是第一列
adjacent.push(emptyBoxIndex - 1);
}
if (
emptyBoxIndex % gridLength !== gridLength - 1 &&
emptyBoxIndex + 1 !== pIndex
) {
// 不是最后一列
adjacent.push(emptyBoxIndex + 1);
}
const m = Math.floor(Math.random() * adjacent.length);
const boxesMapIndexToMove = adjacent[m];
pIndex = emptyBoxIndex;
const pTile = boxesMap[boxesMapIndexToMove];
boxesMap[boxesMapIndexToMove] = boxesMap[emptyBoxIndex];
boxesMap[emptyBoxIndex] = pTile;
switch (emptyBoxIndex - boxesMapIndexToMove) {
case 1:
pos[boxesMap[emptyBoxIndex]][0] += 1;
break;
case gridLength:
pos[boxesMap[emptyBoxIndex]][1] += 1;
break;
case -gridLength:
pos[boxesMap[emptyBoxIndex]][1] -= 1;
break;
case -1:
pos[boxesMap[emptyBoxIndex]][0] -= 1;
break;
}
move(boxesMap[emptyBoxIndex], pos[boxesMap[emptyBoxIndex]]);
emptyBoxIndex = boxesMapIndexToMove;
}
if (steps < 5000) {
window.requestAnimationFrame(walk);
}
};
window.requestAnimationFrame(walk);
预览
控制台