用 JS 做一個數獨游戲(二)


用 JS 做一個數獨游戲(二)

上一篇博客 中,我們通過 Node 運行了我們的 JavaScript 代碼,在控制台中打印出來生成好的數獨終盤。為了讓我們的數獨游戲能有良好的體驗,這篇博客將會為生成好的數獨終盤做一個比較完善的界面。最終的效果如下:

你也可以訪問網頁上的 demo 進行數獨游戲的體驗。

完善挖洞算法

上一篇博客 中提到過挖洞算法,實際上那並不完整,因為算法里面只有生成數獨終盤的部分,並沒有進行挖洞處理(也就是隱藏部分格子)。為了補充完整挖洞的算法,我們在 Game 對象里面加上隨機隱藏格子的代碼:

// class Game
/**
 * 挖去一部分格子,將屬性設為隱藏
 */
digBoard() {
    let dig = 0, block;
    for(let i = 0; i < 3; i++) {
        for(let j = 0; j < 3; j++) {
            for( let k = 0; k < this.digTimes; k++) {
                block = this.board.getBlockGrids(i, j);
                dig   = Math.floor( Math.random() * 9 );

                if( block[dig].isVisible() ) {
                    // avoid duplicated hiding
                    block[dig].setVisible(false);
                } 
            }
        }
    }
    // Utils.printAll(this.board);
}

實際上就是很簡單的取隨機數,在每個 block 塊(一個塊是一個 3x3 的大方格)中進行 n 次循環,每次循環都將隨機的數作為索引,修改塊中的 grid 對象的 visible 屬性,將其設為隱藏。

挖洞法比較簡單,通過預設的三種難度:

Game.DifficutyEasy = 1;
Game.DifficutyNormal = 2;
Game.DifficutyHard = 3;

每種難度隱藏不同數目的格子,然后只要將其顯示在界面上即可。

編寫界面代碼

界面是用網頁的方式實現的,主要的 html 代碼如下:

<div align="center">
    <div id="gamediv" align="center">

    </div>
    <div>
        <p id="result-label" class="result-normal"></p>
    </div>
    <hr />
    <div id="time">
        <p id="time-label">00:00:00</p>
    </div>
    <div id="difficuty">
        <input type="radio" name="difficuty" value="1" onmouseup="changeDifficuty(this.value)" checked="checked" />Easy
        <input type="radio" name="difficuty" value="2" onmouseup="changeDifficuty(this.value)" /> Normal
        <input type="radio" name="difficuty" value="3" onmouseup="changeDifficuty(this.value)" /> Hard
    </div>
    <div id="buttons">
        <button onclick="genBoard()" type="button">Restart game</button>
        <button onclick="tu.startTimer()" type="button">Start Game</button>
    </div>
</div>
<script src="./NumberPlaceCore.js"></script>
<script src="./game.js"></script>

預留了一個 div 用於顯示數獨棋盤。有用時記錄,兩個按鈕,和難度選擇。

數獨棋盤的顯示是由 JavaScript 代碼完成的。首先查找頁面中是否已有數獨棋盤,若已有棋盤,則先將其刪除,再重新創建,這樣做是為了重新開始游戲后保證頁面中只有一個棋盤。

let tBoard;
tBoard = document.getElementById("board");
if( tBoard ) {
    tBoard.remove();
}
tBoard = document.createElement("table");

然后通過循環依次創建各個格子,對於未顯示的值的格子,將其用一個 input 組件表示,留給玩家填數字,最后將填充好的格子添加到預覽的 div 中:

let tr, td, grid, value;
let ginput;
for(let i = 0; i < 9; i++) {
    tr = document.createElement("tr");
    for(let j = 0; j < 9; j++) {
        td = document.createElement("td");
        value = g.getValueAt(new Number(i), new Number(j));
        td.setAttribute("class", "grid-show");
        if( value ) {
            td.innerHTML = value;
        }
        else {
            ginput = document.createElement("input");
            inputs.push(ginput);
            // ... 省略部分代碼
            td.appendChild(ginput);
        }
        tr.appendChild(td);
    }
    tBoard.appendChild(tr);
}

gamediv.appendChild(tBoard);

其中有個 inputs 數組用於記錄待填的格子,每當玩家向格子中填一個數,就會調用函數 placeGrid,將玩家填寫的值傳遞給底層的 board 對象。每次填寫數字時,都會判斷一次是否所有的待填格子都已經填充完畢:

function checkInputs() {
    let valid = true;
    inputs.forEach( e => {
        if( !e.value ) {
            valid = false;
        }
    });
    return valid;
}

若該函數返回 true 的話,那么就應該提示用於游戲結束,給出結果,例如:

總結

這一部分其實比較簡單,涉及到較多的內容是通過 JavaScript 代碼對 DOM 進行操作。但是這部分代碼仍然有些不足:

  1. 計時工具必須要手動點擊 Start Game 按鈕才會開始計時,可以考慮做成玩家進入界面時就開始計時,或者開始填充第一個數時計時。

  2. 缺乏一些提示,可以在提高待填格子數目的情況下,通過某個操作(比如說點擊幫助按鈕顯示某個格子的值)來降低游戲難度,提高可玩性。

  3. 挖洞法的方法是隨機的,不能確定是否在挖完之后的棋盤上填充數字時只有唯一解。

至此,一個簡單的數獨游戲就完成了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM