欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

头脑风暴--原生JS实现汉诺塔游戏

程序员文章站 2022-07-14 15:26:08
...

介绍

今天写了一个汉诺塔游戏,我想大家应该都玩过,先给大家看看具体是什么样吧。
源码已上传github:github链接

头脑风暴--原生JS实现汉诺塔游戏
很遗憾,也就只有3个圆盘我可以顺利通过,哈哈~~~,如果谁可以玩更高的级别,还请不吝赐教啦。话不多说,先看怎么实现吧。

游戏规则

整个小游戏是可以自己调整难度的,演示里我是使用的3个圆盘,大家可以自行调整。当然,也可以改成闯关模式,这就靠大家发挥啦。
汉诺塔游戏规则:只有宽度小的圆盘可以放在宽度大的圆盘上,否则不能放置,把所有圆盘从第一个柱子移动到第三个柱子算游戏完成。

HTML布局

html布局比较简单,大家一看就明白了,直接上代码

<div class="container">
        <div class="cloumns" id="c1">
        </div>
        <div class="cloumns" id="c2"></div>
        <div class="cloumns" id="c3"></div>
        <div class="bot"></div>

         <!-- 胜利时的弹出框 -->
    <div class="success">
        <div>恭喜你,智商超人哦!!</div>
    </div>
    </div>
    //按键控制区
    <div class="btns">
        <div>
            <button data-from="c1" data-to="c3"></button>
            <button data-from="c1" data-to="c2"></button>
        </div>
        <div>
            <button data-from="c2" data-to="c1"></button>
            <button data-from="c2" data-to="c3"></button>
        </div>
        <div>
            <button data-from="c3" data-to="c2"></button>
            <button data-from="c3" data-to="c1"></button>
        </div>
    </div>

CSS代码

css代码更简单啦,配合上面的html代码大家自行看啦,当然我的审美实在不怎么样,所有大家可以自己美化界面

*{
    margin: 0;
    padding: 0;
}

/* 外面父级的样式 */
.container{
    width: 900px;
    height: 600px;
    background-color: #ccc;
    margin: 50px auto 0;
    display: flex;
    justify-content: space-around;
    padding-top: 60px;
    padding-bottom: 30px;
    position: relative;
}

/* 中间三个柱子的样式 */
.container .cloumns{
    width: 30px;
    border-radius: 15px 15px 0 0;
    background-color: #8c8c8c;
    display: flex;
    flex-direction: column-reverse;
}

.container .bot{
    position: absolute;
    left: 0;
    bottom: 0;
    height: 30px;
    width: 100%;
    background-color: #000;
}

/* 每个汉诺塔中的圆盘的样式 */

.container .cloumns > div{
    width: 150px;
    height: 30px;
    border: 1px solid black;
    border-radius: 15px;
    background-color: lightblue;
    margin-left: 50%;
    transform: translateX(-50%);
}

/* 按钮样式 */

.btns{
    display: flex;
    width: 900px;
    margin: 20px auto 0;
    justify-content: space-around;
}
.btns > div > button{
    width: 30px;
    height: 30px;
    margin: 0 1em;
    cursor: pointer;
}

/* 胜利模块的样式 */
.container .success{
    opacity: 0;
    position: absolute;
    width: 100%;
    height: 100%;
    top: 0px;
    display: flex;
    justify-content: center;
    align-items: center;
    background-color:rgba(0, 0, 0, 0.5);
}
.container .success > div{
    width: 200px;
    height: 100px;
    text-align: center;
    line-height: 100px;
    font-size: 16px;
    font-weight: bold;
    background-color: aqua;
    color: #f00;
}

JS代码

好啦,重头戏到了,现在开始讲js代码啦
首先获取页面上的元素,并为每一个柱子创建一个数组,代表每个圆盘上的数量,后面每次移动柱子上的圆盘就比较简单了,只需要操作数组即可。

//获取每个柱子
let c1 = document.getElementById('c1');
let c2 = document.getElementById('c2');
let c3 = document.getElementById('c3');
// 获取所有的按钮
let btns = document.querySelectorAll('button');
//获取胜利的弹出框
let success = document.getElementsByClassName('success')[0];
//创建一个数组,每个柱子的圆盘的数量
//想要增加难度,只需要在数组中添加数字即可
//例如:c1:[4, 3, 2, 1]就会生成四个圆盘了
const cloumns = {
    c1: [3, 2, 1],
    c2: [],
    c3: []
}

到目前为止,界面已经创建完成,每个柱子也已经获取,每个柱子上的圆盘也已经创建,所以接下来就是将这些元素渲染到页面上。
createDom函数负责通过传入的柱子和负责这个柱子的数组中的元素来创建相应的圆盘个数。

//创建每个柱子里的圆盘并渲染页面
function render() {
    //每次加载,清空页面
    createDom(cloumns.c1, c1);
    createDom(cloumns.c2, c2);
    createDom(cloumns.c3, c3);

    function createDom(arr, dom) {
        dom.innerHTML = '';
        for (let i = 0; i < arr.length; i++) {
            const n = arr[i];
            const div = document.createElement('div');
            div.style.width = minWidth + (n - 1) * stepWidth + 'px';
            dom.appendChild(div);
        }
    }
}
render();

给每一个按钮添加点击事件,在这里要注意的是,会形成闭包,因此我在for循环里用的ES6中的let定义

for (let i = 0; i < btns.length; i++) {
    btns[i].onclick = () => {
        var from = cloumns[btns[i].dataset.from];
        var to = cloumns[btns[i].dataset.to];
        move(from, to);
    }
}

为了方便我们获取按钮式向左还是向右,在html中已经给每一个按钮添加了data-from和data-to。通过获取按钮上属性的值可以准确判断出该移动到哪一个柱子上

<div class="btns">
        <div>
            <button data-from="c1" data-to="c3"></button>
            <button data-from="c1" data-to="c2"></button>
        </div>
        <div>
            <button data-from="c2" data-to="c1"></button>
            <button data-from="c2" data-to="c3"></button>
        </div>
        <div>
            <button data-from="c3" data-to="c2"></button>
            <button data-from="c3" data-to="c1"></button>
        </div>
    </div>

移动规则

游戏规则是只能小圆盘放在大圆盘上,因此在每次移动之前都需要判断下一个要移动的柱子的最顶层圆盘是否比正在移动的这个大,如果比正在移动的这个圆盘大,则可以进行移动,反之,则不行。
当第一个柱子和第二个柱子上的圆盘都为0的时候,游戏结束。在这里大家可以动脑思考怎么样改造成闯关类型游戏哦

//判断两个柱子的最顶层的圆盘大小,并且进行胜负判断
function check(from, to){
    const fromLast = from[from.length - 1];
    const toLast = to[to.length - 1];
    if(fromLast < toLast){
        to.push(from.pop());
        //每次改变需要重新渲染
        render();
    }else{
        return;
    }
    if(cloumns.c1.length === 0 && cloumns.c2.length === 0){
        success.style.opacity = 1;
        for(let i = 0; i < btns.length; i++){
            btns[i].style.opacity = 0;
        }
    }
}

结语

整个小游戏就完成了,这个游戏不难,但是可以很好的锻炼逻辑思维能力,我比较喜欢。写出来之后还能自己检验自己能玩多少个圆盘,哈哈。反正我玩3个圆盘是得心应手,再多了就有点困难咯。