扫雷

作者: 升龙无涯 | 来源:发表于2021-09-04 09:05 被阅读0次

    在以前的win7系统中,自带的小游戏中,有一款游戏叫扫雷,效果如下图:

    扫雷
    html中的结构代码如下:
    <select name="mineNum">
        <option value="0">请选择雷的数量</option>
        <option value="10-8">10个雷</option>
        <option value="40-16">40个雷</option>
        <option value="99-32">99个雷</option>
    </select>
    剩余雷数量:<span class="mineNum">0</span>
    

    js逻辑代码中,预置两个工具函数:

    // 设置样式的函数
    function setStyle(ele, styleObj){
        for(var attr in styleObj){
            ele.style[attr] = styleObj[attr];
        }
    }
    // 获取随机数的函数
    function getRandom(a,b=0){
        var max = a;
        var min = b;
        if(a<b){
            max = b;
            min = a;
        }
        return Math.floor(Math.random() * (max - min)) + min;
    }
    

    首先要根据选中的雷的数量,来创建小盒子:

    // 获取标签
    var mineSelect = document.querySelector('[name="mineNum"]');
    var mineNumBox = document.querySelector('.mineNum');
    // 获取扫雷游戏需要的列的数量
    mineSelect.onchange = function(){
        // 获取当前选中的option的value
        var value = this.value;
        if(value === '0'){
            alert("请选择雷的数量")
            return false;
        }
        // 从中获取到类的数量和扫雷需要的列的数量
        var mineNum = +value.split('-')[0]
        var col = +value.split('-')[1]
        // 如果页面中已经有扫雷游戏了,就将之前的删除
        var mine = document.querySelector('.mine');
        if(mine){
            document.body.removeChild(mine)
        }
        // 调用创建扫雷游戏的函数
        createMine(mineNum,col)
    }
    // 创建扫雷游戏的函数
    function createMine(mineNum,col){
        // 根据列的数量创建大盒子
        var box = document.createElement('div')
        // 设置类名
        box.className = 'mine';
        document.body.appendChild(box)
        // 不能选中box中的内容
        box.onselectstart = function(){
            return false
        }
        // 设置样式
        setStyle(box,{
            border:"3px solid #00f",
            position:"relative",
            width:col*20 + 'px',
            height:col*20 + 'px',
        })
        // 在大盒子中创建小盒子
        for(var i=0;i<Math.pow(col,2);i++){
            var div = document.createElement('div')
            box.appendChild(div)
            setStyle(div,{
                width:"18px",
                height:"18px",
                border:"1px solid #fff",
                position:"absolute",
                left:i%col*20+'px',
                top:Math.floor(i/col)*20 + 'px',
                backgroundColor:"#aaa"
            })
        }
        // 调用随机设置雷的函数
        var indexArr = setMine(box,mineNum,col)
        // 调用计算雷数量的函数
        countMine(box,col)
        // 点击小div开始扫
        clearance(box,col,indexArr)
    }
    

    设置雷的函数如下:

    // 设置随机雷的函数
    function setMine(ele,num,col){
        // 在ele中创建num个雷
        // 定义数组用来存放是雷的小div的下标
        var indexArr = []
        for(var i=0;i<num;i++){
            // 获取随机下标
            var randomIndex = getRandom(ele.children.length)
            // 判断随机下标是否在数组中
            var index = indexArr.indexOf(randomIndex)
            // 如果这个随机下标不在数组中,就将这个随机下标放当数组中
            if(index<0){
                indexArr.push(randomIndex)
            }else{
                // 这次循环作废 - 重新创建随机下标 - 要保证数组中随机下标的个数一定是雷的数量
                i--
            }
        }
        // indexArr中存放的是所有 是雷的div的下标
        // 给所有是雷的div做特殊的标记
        for(var i=0;i<indexArr.length;i++){
            ele.children[indexArr[i]].mine = true;
            // ele.children[indexArr[i]].style.backgroundColor = 'red';
        }
        // 更改页面中雷的数量
        mineNumBox.innerText = num
        return indexArr
    }
    

    根据设置好的雷,给每个小div计算周围雷的数量:

    // 计算雷数量的函数
    function countMine(ele,col){
        // 遍历每个小div,计算周围雷的数量
        for(var i=0;i<ele.children.length;i++){
            // 如果当前div是雷就跳过
            if(ele.children[i].mine){
                continue
            }
            // 获取周围所有div的下标的数组
            var arr = getIndexArr(i,col);
            // 定义当前div周围雷的数量变量
            var num = 0
            // 遍历周围的div计算
            for(var j=0;j<arr.length;j++){
                if(ele.children[i+arr[j]].mine){
                    num++
                }
            }
            ele.children[i].num = num;
            // ele.children[i].innerText = num;
        }
    }
    

    其中获取周围div的下标数组的代码如下:

    // 获取每个div周围的div下标的数组
    function getIndexArr(index,col){
        // 定义周围的div下标的数组
        var arr = [1,-1,col,-col,col+1,col-1,-col-1,-col+1];
        if(index<col){
            arr = [-1,1,col,col-1,col+1];
        }
        // 如果是最后1行,周围只有5个div - arr数组中就应该只有5个下标
        if(Math.floor(index/col) === col-1){
            arr = [-1,1,-col,-col-1,-col+1];
        }
        // 如果是第1列,周围只有5个div - arr数组中就应该只有5个下标
        if(index%col === 0){
            arr = [col,col+1,1,-col,-col+1];
        }
        // 如果是最后1列,周围只有5个div - arr数组中就应该只有5个下标
        if((index+1)%col === 0){
            arr = [-col-1,-col,-1,col-1,col];
        }
        // 如果是左上角的div,周围只有3个div - arr数组中就应该只有3个下标
        if(index===0){
            arr = [1,col,col+1];
        }
        // 如果是左下角的div,周围只有3个div - arr数组中就应该只有3个下标
        if(index===(col-1)*col){
            arr = [1,-col,-col+1];
        }
        // 如果是右下角的div,周围只有3个div - arr数组中就应该只有3个下标
        if(index===col*col-1){
            arr = [-1,-col,-col-1];
        }
        // 如果是右上角的div,周围只有3个div - arr数组中就应该只有3个下标
        if(index===col-1){
            arr = [-1,col,col-1];
        }
        return arr
    }
    

    再下来就可以开始玩游戏了,开始扫雷的代码如下:

    // 点击小div开始扫的函数
    function clearance(ele,col,indexArr){
        // 遍历所有小div绑定事件
        for(let i=0;i<ele.children.length;i++){
            // 单击事件 - 如果不是雷,就将周围雷的数量显示出来 - 如果周围没有雷就不显示数量,继续将周围的div点开
            ele.children[i].onclick = function(){
                if(!this.mine){
                    // 如果点击的不是雷,就打开
                    openNow(this,i,col,ele)
                }else{
                    alert("GAME OVER");
                    // 如果点击的div是雷,就将所有类引爆,并结束游戏
                    for(var j=0;j<indexArr.length;j++){
                        ele.children[indexArr[j]].style.backgroundColor = 'red';
                    }
                }
            }
            // 右击事件,标记雷
            ele.children[i].oncontextmenu = function(){
                // 将雷标红
                this.style.backgroundColor = 'red';
                mineNumBox.innerText = mineNumBox.innerText-1
                // 阻止默认行为
                return false;
            }
        }
    }
    

    打开当前div的函数如下:

    // 打开当前小div,设置不同的背景颜色,并判断是否需要递归打开
    function openNow(nowEle,i,col,ele){
        // 给已经打开的div做标记
        nowEle.open = true;
        // 设置打开的div的背景颜色
        nowEle.style.backgroundColor = '#eee';
        // 如果数量是0就继续打开
        if(nowEle.num === 0){
            // 继续打开周围的div
            open(ele,i,col)
        }else{
            // 如果数量不是0就显示数量
            nowEle.innerText = nowEle.num;
            nowEle.style.textAlign = 'center'
            nowEle.style.lineHeight = '20px'
            nowEle.style.fontSize = '12px'
            nowEle.style.color = '#666'
        }
    }
    

    如果当前div周围雷的数量为0,就将周围的div也打开,需要递归,函数如下:

    // 继续打开周围div的函数
    function open(ele,index,col){
        // 遍历周围的div - 如果雷的数量不是0,就显示数量,如果雷的数量是雷就继续递归打开
        var arr = getIndexArr(index,col);
        // 遍历数组,判断周围div是否打开
        for(var i=0;i<arr.length;i++){
            if(ele.children[index+arr[i]].open){
                continue;
            }else{
                openNow(ele.children[index+arr[i]],index+arr[i],col,ele)
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:扫雷

          本文链接:https://www.haomeiwen.com/subject/ztlkwltx.html