CSPJ 的时候瞎写的。稍微改了一点。源码在后面。

<html>

<head>
    <title>Minesweeper</title>
    <style>
        .unknown {
            background-color: grey;
            color: grey;
        }

        .marked {
            background-color: black;
            color: black;
        }

        .mine {
            background-color: red;
            color: black;
        }

        .open {
            background-color: white;
            color: black;
        }

        td {
            border: 1px solid black;
            height: 2.5em;
            width: 2.2em;
            text-align: center;
        }
    </style>
</head>

<body>
    <div>
        <p>Width: <input id="width" /></p>
        <p>Height: <input id="height" /></p>
        <p>Mines: <input id="mines" /></p>
        <button id="gen">Generate</button>
    </div>
    <table id="table">
    </table>
    <script>
        let wd = document.getElementById("width");
        let hd = document.getElementById("height");
        let md = document.getElementById("mines");
        let gb = document.getElementById("gen");
        let tb = document.getElementById("table");
        let mp = [];
        let dx = [-1, 0, 1, -1, 1, -1, 0, 1];
        let dy = [-1, -1, -1, 0, 0, 1, 1, 1];
        function rf(s) {
            return Math.floor(Math.random() * s);
        }
        let style = ["unknown", "marked", "mine", "open"];
        let mkd = 0, st = 0, ed = 0, gmc = 0, ebf = 1;
        function end() {
            if (ebf) {
                return;
            }
            ebf = 1;
            ed = Date.now();
            let p = document.createElement("p");
            p.innerHTML = `Finished. You used ${(ed - st) / 1000} seconds.`;
            document.body.appendChild(p);
        }
        class Block {
            td;
            mine;
            _state; // unknown, marked, mine, open
            around;
            get state() {
                return this._state;
            }
            set state(v) {
                if (this._state == 1 || this._state == 2 || this._state == 0) {
                    mkd--;
                }
                if (v == 1 || v == 2 || v == 0) {
                    mkd++;
                }
                if (mkd == gmc) {
                    end();
                }
                this.td.classList = style[v];
                this._state = v;
                if (v == 2) {
                    this.td.innerHTML = "M";
                }
                else if (v == 3) {
                    this.td.innerHTML = this.around ? this.around : "";
                }
                else {
                    this.td.innerHTML = "";
                }
            }
            constructor() {
                this.td = document.createElement("td");
                this.mine = 0;
                this.state = 0;
            }
        }
        function gen(w, h, m) {
            mkd = 0;
            gmc = m;
            tb.innerHTML = "";
            mp = [];
            for (let i = 0; i < w; i++) {
                let tr = document.createElement("tr");
                mp[i] = [];
                for (let j = 0; j < h; j++) {
                    let bl = new Block();
                    mp[i][j] = bl;
                    tr.appendChild(bl.td);
                }
                tb.appendChild(tr);
            }
            for (let i = 0; i < m; i++) {
                let x = rf(w), y = rf(h);
                while (mp[x][y].mine) {
                    x = rf(w), y = rf(h);
                }
                mp[x][y].mine = 1;
            }
            function chk(x, y) {
                return x >= 0 && x < w && y >= 0 && y < h;
            }
            function opendfs(x, y) {
                mp[x][y].state = 3;
                if (mp[x][y].around) {
                    return;
                }
                for (let k = 0; k < 8; k++) {
                    let i = x + dx[k], j = y + dy[k];
                    if (chk(i, j) && mp[i][j].state == 0) {
                        opendfs(i, j);
                    }
                }
            }
            function tryopen(i, j) {
                if (mp[i][j].state == 0) {
                    if (mp[i][j].mine) {
                        mp[i][j].state = 2;
                    }
                    else {
                        opendfs(i, j);
                    }
                }
                else if (mp[i][j].state == 3) {
                    let ct = 0;
                    for (let k = 0; k < 8; k++) {
                        let x = i + dx[k], y = j + dy[k];
                        if (chk(x, y) && (mp[x][y].state == 1 || mp[x][y].state == 2)) {
                            ct++;
                        }
                    }
                    if (ct != mp[i][j].around) {
                        return;
                    }
                    for (let k = 0; k < 8; k++) {
                        let x = i + dx[k], y = j + dy[k];
                        if (chk(x, y) && mp[x][y].state == 0) {
                            tryopen(x, y);
                        }
                    }
                }
            }
            for (let i = 0; i < w; i++) {
                for (let j = 0; j < h; j++) {
                    mp[i][j].td.addEventListener("click", () => { // open
                        tryopen(i, j);
                    });
                    mp[i][j].td.addEventListener("contextmenu", (e) => { // mark
                        e.preventDefault();
                        if (mp[i][j].state == 0) {
                            mp[i][j].state = 1;
                        }
                        else if (mp[i][j].state == 1) {
                            mp[i][j].state = 0;
                        }
                    });
                    if (mp[i][j].mine) {
                        continue;
                    }
                    let res = 0;
                    for (let k = 0; k < 8; k++) {
                        let x = i + dx[k], y = j + dy[k];
                        if (chk(x, y) && mp[x][y].mine) {
                            res++;
                        }
                    }
                    mp[i][j].around = res;
                }
            }
            ebf = 0;
            st = Date.now();
        }
        gb.addEventListener("click", () => {
            let w = Number(wd.value);
            let h = Number(hd.value);
            let m = Number(md.value);
            if (!isNaN(w) && !isNaN(h) && !isNaN(m) && 1 <= w && w <= 30 && 1 <= h && h <= 30 && m < h * w) {
                gen(w, h, m);
            }
        });
        gen(10, 10, 10);
    </script>
</body>

</html>

考 CSPJ 的时候写的,瞎玩了一个小时。

<html>

<head>
    <title>Minesweeper</title>
    <style>
        .unknown {
            background-color: grey;
            color: grey;
        }

        .marked {
            background-color: black;
            color: black;
        }

        .mine {
            background-color: red;
            color: black;
        }

        .open {
            background-color: white;
            color: black;
        }

        td {
            border: 1px solid black;
            height: 2.5em;
            width: 2.2em;
            text-align: center;
        }
    </style>
</head>

<body>
    <div>
        <p>Width: <input id="width" /></p>
        <p>Height: <input id="height" /></p>
        <p>Mines: <input id="mines" /></p>
        <button id="gen">Generate</button>
    </div>
    <table id="table">
    </table>
    <script>
        let wd = document.getElementById("width");
        let hd = document.getElementById("height");
        let md = document.getElementById("mines");
        let gb = document.getElementById("gen");
        let tb = document.getElementById("table");
        let mp = [];
        let dx = [-1, 0, 1, -1, 1, -1, 0, 1];
        let dy = [-1, -1, -1, 0, 0, 1, 1, 1];
        function rf(s) {
            return Math.floor(Math.random() * s);
        }
        let style = ["unknown", "marked", "mine", "open"];
        let mkd = 0, st = 0, ed = 0, gmc = 0;
        function end() {
            ed = Date.now();
            let p = document.createElement("p");
            p.innerHTML = `Finished. You used ${(ed - st) / 1000} seconds.`;
            document.body.appendChild(p);
        }
        class Block {
            td;
            mine;
            _state; // unknown, marked, mine, open
            around;
            get state() {
                return this._state;
            }
            set state(v) {
                if (this._state == 1 || this._state == 2) {
                    mkd--;
                }
                if (v == 1 || v == 2) {
                    mkd++;
                }
                if (mkd == gmc) {
                    end();
                }
                this.td.classList = style[v];
                this._state = v;
                if (v == 2) {
                    this.td.innerHTML = "M";
                }
                else if (v == 3) {
                    this.td.innerHTML = this.around ? this.around : "";
                }
                else {
                    this.td.innerHTML = "";
                }
            }
            constructor() {
                this.td = document.createElement("td");
                this.mine = 0;
                this.state = 0;
            }
        }
        function gen(w, h, m) {
            mkd = 0;
            gmc = m;
            tb.innerHTML = "";
            mp = [];
            for (let i = 0; i < w; i++) {
                let tr = document.createElement("tr");
                mp[i] = [];
                for (let j = 0; j < h; j++) {
                    let bl = new Block();
                    mp[i][j] = bl;
                    tr.appendChild(bl.td);
                }
                tb.appendChild(tr);
            }
            for (let i = 0; i < m; i++) {
                let x = rf(w), y = rf(h);
                while (mp[x][y].mine) {
                    x = rf(w), y = rf(h);
                }
                mp[x][y].mine = 1;
            }
            function chk(x, y) {
                return x >= 0 && x < w && y >= 0 && y < h;
            }
            function opendfs(x, y) {
                mp[x][y].state = 3;
                if (mp[x][y].around) {
                    return;
                }
                for (let k = 0; k < 8; k++) {
                    let i = x + dx[k], j = y + dy[k];
                    if (chk(i, j) && mp[i][j].state == 0) {
                        opendfs(i, j);
                    }
                }
            }
            function tryopen(i, j) {
                if (mp[i][j].state == 0) {
                    if (mp[i][j].mine) {
                        mp[i][j].state = 2;
                    }
                    else {
                        opendfs(i, j);
                    }
                }
                else if (mp[i][j].state == 3) {
                    let ct = 0;
                    for (let k = 0; k < 8; k++) {
                        let x = i + dx[k], y = j + dy[k];
                        if (chk(x, y) && (mp[x][y].state == 1 || mp[x][y].state == 2)) {
                            ct++;
                        }
                    }
                    if (ct != mp[i][j].around) {
                        return;
                    }
                    for (let k = 0; k < 8; k++) {
                        let x = i + dx[k], y = j + dy[k];
                        if (chk(x, y) && mp[x][y].state == 0) {
                            tryopen(x, y);
                        }
                    }
                }
            }
            for (let i = 0; i < w; i++) {
                for (let j = 0; j < h; j++) {
                    mp[i][j].td.addEventListener("click", () => { // open
                        tryopen(i, j);
                    });
                    mp[i][j].td.addEventListener("contextmenu", (e) => { // mark
                        e.preventDefault();
                        if (mp[i][j].state == 0) {
                            mp[i][j].state = 1;
                        }
                        else if (mp[i][j].state == 1) {
                            mp[i][j].state = 0;
                        }
                    });
                    if (mp[i][j].mine) {
                        continue;
                    }
                    let res = 0;
                    for (let k = 0; k < 8; k++) {
                        let x = i + dx[k], y = j + dy[k];
                        if (chk(x, y) && mp[x][y].mine) {
                            res++;
                        }
                    }
                    mp[i][j].around = res;
                }
            }
            st = Date.now();
        }
        gb.addEventListener("click", () => {
            let w = Number(wd.value);
            let h = Number(hd.value);
            let m = Number(md.value);
            if (!isNaN(w) && !isNaN(h) && !isNaN(m) && 1 <= w && w <= 30 && 1 <= h && h <= 30 && m < h * w) {
                gen(w, h, m);
            }
        });
        gen(10, 10, 10);
    </script>
</body>

</html>