天天看點

使用 HTML、CSS、JavaScript 建立一個簡單的井字遊戲(02)

現在我們将編寫一些實用函數。在isValidAction函數中,我們将決定使用者是否想要執行有效的操作。如果 tile 的内部文本是XorO我們傳回 false 作為操作無效,否則 tile 為空是以操作有效。

const isValidAction = (tile) => {
    if (tile.innerText === 'X' || tile.innerText === 'O'){
        return false;
    }
    return true;
};      

下一個效用函數将非常簡單。在這個函數中,我們将接收一個索引作為參數,并将棋盤數組中的相應元素設定為我們目前玩家的符号。

const updateBoard =  (index) => {
   board[index] = currentPlayer;
}      

我們将編寫一個小函數來處理玩家的變化。在這個函數中,我們将首先從playerDisplay. 字元串模闆文字player${currentPlayer}将成為playerX或playerO取決于目前玩家。接下來,我們将使用三元表達式來更改目前玩家的值。如果是X,它将是O否則它将是X。現在,我們改變了我們使用者的價值,我們需要更新innerText的playerDisplay,并應用新的播放器類的。

const changePlayer = () => {
    playerDisplay.classList.remove(`player${currentPlayer}`);
    currentPlayer = currentPlayer === 'X' ? 'O' : 'X';
    playerDisplay.innerText = currentPlayer;
    playerDisplay.classList.add(`player${currentPlayer}`);
}      

現在我們将編寫宣布最終遊戲結果的 announer 函數。它将接收結束遊戲類型并innerText根據結果更新播音員 DOM 節點的 。在最後一行中,我們必須删除隐藏類,因為播音員預設是隐藏的,直到遊戲結束。

const announce = (type) => {
    switch(type){
       case PLAYERO_WON:
            announcer.innerHTML = 'Player <span class="playerO">O</span> Won';
            break;
       case PLAYERX_WON:
            announcer.innerHTML = 'Player <span class="playerX">X</span> Won';
            break;
       case TIE:
            announcer.innerText = 'Tie';
        }
    announcer.classList.remove('hide');
};      

接下來我們将編寫這個項目中最有趣的部分之一——結果評估。首先,我們将建立一個 roundWon 變量并将其初始化為 false。然後我們将周遊winConditions數組并檢查棋盤上的每個獲勝條件。例如,在第二次疊代中,我們将檢查這些值:board3、board4、board5。

我們還将進行一些優化,如果任何字段為空,我們将調用continue并跳到下一次疊代,因為如果獲勝條件中有空圖塊,您将無法獲勝。如果所有字段都相等,那麼我們就有一個赢家,是以我們将 roundWon 設定為 true 并中斷 for 循環,因為任何進一步的疊代都會浪費計算。

在循環之後,我們将檢查roundWon變量的值,如果為真,我們将宣布獲勝者并将遊戲設定為非活動狀态。如果我們沒有獲勝者,我們将檢查棋盤上是否有空牌,如果我們沒有獲勝者并且沒有空牌,我們将宣布平局。

function handleResultValidation() {
  let roundWon = false;
  for (let i = 0; i <= 7; i++) {
    const winCondition = winningConditions[i];
    const a = board[winCondition[0]];
    const b = board[winCondition[1]];
    const c = board[winCondition[2]];
    if (a === "" || b === "" || c === "") {
      continue;
    }
    if (a === b && b === c) {
      roundWon = true;
      break;
    }
  }

  if (roundWon) {
    announce(currentPlayer === "X" ? PLAYERX_WON : PLAYERO_WON);
    isGameActive = false;
    return;
  }

  if (!board.includes("")) announce(TIE);
}

      

接下來我們将處理使用者的操作。此函數将接收一個 tile 和一個索引作為參數。當使用者單擊一個圖塊時,将調用此函數。首先我們需要檢查它是否是一個有效的動作,我們還将檢查遊戲目前是否處于活動狀态。如果兩者都為真,我們innerText用目前玩家的符号更新瓷磚的 ,添加相應的類并更新闆陣列。現在一切都更新了,我們必須檢查遊戲是否已經結束,是以我們調用handleResultValidation(). 最後,我們必須調用該changePlayer方法将輪次傳遞給另一個玩家。

const userAction = (tile, index) => {
  if (isValidAction(tile) && isGameActive) {
    tile.innerText = currentPlayer;
    tile.classList.add(`player${currentPlayer}`);
    updateBoard(index);
    handleResultValidation();
    changePlayer();
  }
};      

為了讓遊戲正常運作,我們必須向磁貼添加事件偵聽器。我們可以通過循環周遊圖塊數組并為每個圖塊添加一個事件偵聽器來做到這一點。(為了獲得更好的性能,我們隻能向容器添加一個事件偵聽器并使用事件冒泡來捕獲父級上的磁貼點選,但我認為對于初學者來說這更容易了解。)

tiles.forEach( (tile, index) => {
    tile.addEventListener('click', () => userAction(tile, index));
});      

我們隻錯過了一項功能:重置遊戲。為此,我們将編寫一個resetBoard函數。在此函數中,我們将棋盤設定X為由九個空字元串組成,将遊戲設定為活動狀态,移除播音員并将玩家更改回(根據定義X始終開始)。

我們必須做的最後一件事是周遊圖塊并将innerText 設定回空字元串,并從圖塊中删除任何特定于玩家的類。

const resetBoard = () => {
    board = ['', '', '', '', '', '', '', '', ''];
    isGameActive = true;
    announcer.classList.add('hide');
    if (currentPlayer === 'O') {
        changePlayer();
    }
    tiles.forEach(tile => {
        tile.innerText = '';
        tile.classList.remove('playerX');
        tile.classList.remove('playerO');
    });
}      

現在我們隻需要将此函數注冊為重置按鈕的點選事件處理程式。

resetButton.addEventListener('click', resetBoard);      

就是這樣,我們有一個功能齊全的井字遊戲,你可以和你的朋友一起玩,玩得開心。

繼續閱讀