汉诺塔游戏

近期一直在玩的游戏是汉诺塔,我倒是觉得这个游戏挺解乏的,但是我女票子却不喜欢,我让她玩 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>

作者: 曾小乱

喜欢写点有意思的东西

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据