掃雷

在以前的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)
        }
    }
}
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。