近期一直在玩的游戏是汉诺塔,我倒是觉得这个游戏挺解乏的,但是我女票子却不喜欢,我让她玩 5 层,她讨价还价成 4 层,我再坚持一次,她就说不玩了不玩了,那就陪她玩 4 层咯。下面,我们来看看 js 制作的简单动画展示,这个游戏应该怎么玩。
汉诺塔的思路是递归,用来学习编程思想非常有帮助。我们说一般递归可以解决的问题,也可以用动态规划的思路去做,这个我还没有实现。
相传如果能完成 64 个叠加的圆盘,宇宙将会毁灭。我尝试玩了 10 个,用人脑去递归,贼痛苦呀。
代码在下面写得简陋勿喷。
<script src="http://snapsvg.io/assets/js/snap.svg-min.js"></script>
<svg id="svg" style="width: 100%; height: 100%;"></svg>
<script>
let step = 0;
function hanoi(n, a, b, c) {
if (n === 1) {
step++;
console.log(step + ": ", a, "--->", c);
let rect;
if (a === "A") {
rect = dataA.pop();
} else if (a === "B") {
rect = dataB.pop();
} else if (a === "C") {
rect = dataC.pop();
}
if (c === "A") {
dataA.push(rect);
} else if (c === "B") {
dataB.push(rect);
} else if (c === "C") {
dataC.push(rect);
}
draw(deepClone(dataA), deepClone(dataB), deepClone(dataC), step);
} else {
hanoi(n - 1, a, c, b);
hanoi(1, a, b, c);
hanoi(n - 1, b, a, c);
}
}
function isObject(v) {
return Object.prototype.toString.call(v) === "[object Object]";
}
function deepClone(data) {
if (Array.isArray(data)) {
let arr = [];
for (const d of data) {
arr.push(deepClone(d));
}
return arr;
} else if (isObject(data)) {
let obj = {};
for (let k in data) {
if (isObject(data[k])) {
obj[k] = deepClone(data[k]);
} else {
obj[k] = data[k];
}
}
return obj;
} else {
return data;
}
}
let svg = Snap("#svg");
let count = 5;
let maxWidth = 100;
let stepWidth = 10;
let maxHeight = 100;
let height = 20;
let maxY = 100;
let dataA = [];
let dataB = [];
let dataC = [];
for (let i = 0; i < count; i++) {
let width = maxWidth - stepWidth * i;
dataA.push({
width,
fill:
"#" +
("000000" + String(Math.random() * 0xffffff).toString(16)).slice(-6),
});
}
for (let i = 0; i < dataA.length; i++) {
let { width, fill } = dataA[i];
svg
.rect(
(maxWidth - width) / 2,
maxHeight - height * i,
width,
height,
10,
10
)
.attr({
fill,
});
}
hanoi(count, "A", "B", "C");
function draw(dataA, dataB, dataC, step) {
setTimeout(
(dataA, dataB, dataC) => {
console.log(dataA, dataB, dataC);
svg.clear();
let datas = [dataA, dataB, dataC];
for (let j = 0; j < datas.length; j++) {
let data = datas[j];
for (let i = 0; i < data.length; i++) {
let { width, fill } = data[i];
let gapWidth = 120;
svg
.rect(
gapWidth * j + (maxWidth - width) / 2,
maxHeight - height * i,
width,
height,
10,
10
)
.attr({
fill,
});
}
}
},
1000 * step,
dataA,
dataB,
dataC
);
}
</script>