HTML+原生JavaScript实现扫雷小游戏

前端小练习:扫雷

总叙

一个简单的前端小练习。扫雷游戏的规则大家都知道,如果要用一个前端页面的形式实现这个游戏,由于扫雷盘的大小和地雷数量都是用户输入的,并且地雷的位置需要随机生成,因此需要嵌入大量JavaScript代码来辅助动态生成。相信对前端开发初学者和入门一段时间的前端开发者来说都是一次非常合适的练手。

功能展示

用户可以自定义扫雷游戏的规模。进行游戏时,用户可以左键单击一个未翻开的地块,如果埋有地雷则游戏失败;否则将该地块翻开,展示其周围8个地块中埋藏的地雷数量。

初始界面

请添加图片描述

游戏中界面

请添加图片描述

游戏结束界面

请添加图片描述
请添加图片描述

参考实现

<!DOCTYPE html>
<html lang="zh">
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>扫雷</title>
    </head>
    <style>
        body {
            width: 100%;
            height: 100%;  /* 会在JavaScript代码中显式设定为浏览器窗口高度 */
            margin: 0;
        }
    </style>
    <body>
        <div style="display: flex; align-items: center; width: 100%; height: 100%;">
            <div style="margin: auto;" id="input">

            </div>
            <div style="margin: auto;" id="main">

            </div>
        </div>
    </body>
    <script>
        function onWindowChange() {
            document.body.style.height = `${window.innerHeight}px`;
        }
        window.addEventListener("resize", onWindowChange);
        onWindowChange();
        let flag = false;  // 若为真,说明本局游戏已经结束
        let M = 10, N = 12, C = 3;  // M行N列,C个地雷
        let array = buildArray();
        // 0:未翻开,无雷
        // 1:未翻开,有雷
        // 2:已翻开,无雷
        function buildArray() {
            let array = Array.from(
                { length: M }, 
                function() {
                    return Array.from(
                        { length: N },
                        function() {
                            return 0;
                        }
                    )
                }
            );
            function sum() {
                let count = 0;
                for (let i = 0; i < M; i += 1) {
                    for (let j = 0; j < N; j += 1) {
                        count += array[i][j];
                    }
                }
                return count;
            }
            while (sum() < C) {
                const val = Math.floor(Math.random() * M * N);
                const row = Math.floor(val / N);
                const col = val - row * N;
                array[row][col] = 1;
            }
            return array;
        }
        function onInputClick() {
            const inputM = document.getElementById("input-m");
            const inputN = document.getElementById("input-n");
            const inputC = document.getElementById("input-c");
            M = Number.parseInt(inputM.value);
            N = Number.parseInt(inputN.value);
            C = Number.parseInt(inputC.value);
            if (Number.isNaN(M) || Number.isNaN(N) || Number.isNaN(C)) {
                window.alert("非整数输入值!");
                return;
            }
            if (M <= 0 || N <= 0 || C > M * N / 2) {
                window.alert("输入值范围非法!\n检查行列数为正整数,\n且地雷数不超过格子总数的一半");
                return;
            }
            newGame();
        }
        function buildInput() {
            const inputDiv = document.getElementById("input");
            let inputDivInnerHTML = "";
            inputDivInnerHTML += `<div><label>行 数:<input type="text" value="${M}" id="input-m" /></label></div>`;
            inputDivInnerHTML += `<div><label>列 数:<input type="text" value="${N}" id="input-n" /></label></div>`;
            inputDivInnerHTML += `<div><label>地雷数:<input type="text" value="${C}" id="input-c" /></label></div>`;
            inputDivInnerHTML += "<div style=\"text-align: center; margin: 2px;\"><input type=\"button\" οnclick=\"onInputClick()\" value=\"新游戏\" /></div>";
            inputDiv.innerHTML = inputDivInnerHTML;
        }
        function getId(i, j) {
            return `generated_block_id_${i}_${j}`;
        }
        function getNum(i, j) {
            let count = 0;
            function judge(i, j) {
                if (i < 0 || i >= M || j < 0 || j >= N) {
                    return 0;
                } else if (array[i][j] == 1) {
                    return 1;
                } else {
                    return 0;
                }
            }
            [-1, 0, 1].forEach(function(_i) {
                [-1, 0, 1].forEach(function(_j) {
                    if (_i != 0 || _j != 0) {
                        count += judge(i + _i, j + _j);
                    }
                });
            });
            return count;
        }
        function checkWin() {
            let result = true;
            array.forEach(function(row) {
                row.forEach(function(value) {
                    if (value === 0) {
                        result = false;
                    }
                });
            });
            return result;
        }
        function showLoss() {
            for (let i = 0; i < M; i += 1) {
                for (let j = 0; j < N; j += 1) {
                    if (array[i][j] === 1) {
                        const id = getId(i, j);
                        const block = document.getElementById(id);
                        block.style.backgroundColor = "red";
                        block.style.color = "white";
                        block.innerText = "×";
                    }
                }
            }
        }
        function onClick(i, j) {
            if (flag) {
                
            } else if (i < 0 || i >= M || j < 0 || j >= N) {

            } else if (array[i][j] === 1) {
                flag = true;
                showLoss();
                window.alert("你输了!");
            } else if (array[i][j] === 2) {
                
            } else if (array[i][j] === 0) {
                array[i][j] = 2;
                let block = document.getElementById(getId(i, j));
                block.style.backgroundColor = "rgba(0, 0, 0, 0)";
                const num = getNum(i, j);
                block.innerText = `${num}`;
                if (checkWin()) {
                    flag = true;
                    window.alert("你赢了!");
                }
                if (num === 0) {
                    for (let _i = -1; _i <= 1; _i += 1) {
                        for (let _j = -1; _j <= 1; _j += 1) {
                            onClick(_i + i, _j + j);
                        }
                    }
                }
            }
        }
        function buildMain() {
            const mainDiv = document.getElementById("main");
            let mainInnerHTML = "";
            for (let i = 0; i < M; i += 1) {
                var oneLine = "<div>";
                for (let j = 0; j < N; j += 1) {
                    const style = "width: 1rem;" 
                                + " height: 1rem;" 
                                + " background-color: gray;" 
                                + " display: inline-block;" 
                                + " text-align: center;"
                                + " margin: 2px;";
                    const oneBlock = `<div style="${style}" οnclick="onClick(${i}, ${j})" id="${getId(i, j)}"></div>`;
                    oneLine += oneBlock;
                }
                oneLine += "</div>";
                mainInnerHTML += oneLine;
            }
            mainDiv.innerHTML = mainInnerHTML;
        }
        function newGame() {
            flag = false;
            array = buildArray();
            buildInput();
            buildMain();
        }
        newGame();
    </script>
</html>
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值