井字棋游戏报错Uncaught TypeError: Cannot read properties of undefined (reading '0')求修复
井字棋游戏错误分析与修正
错误原因
未传入参数导致类型错误
在makeMove函数中调用checkWinner()时未传入棋盘状态参数,使得checkWinner函数内的board参数为undefined。当函数遍历获胜条件数组时,尝试访问board[a](如board[0])就会触发Uncaught TypeError: Cannot read properties of undefined (reading '0')错误。全局状态被递归调用意外修改
checkWinner函数中直接修改全局的gameActive变量,而AI的minimax算法会递归调用checkWinner模拟各种走法,这会导致全局gameActive被提前设为false,打断正常游戏流程(比如AI还未完成落子,游戏就被判定结束)。
修正后的完整代码
HTML
<div id="board">board</div> <div id="message">message</div> <button id="resetBtn" type="button">Start/Reset</button>
CSS
#board{ max-width: 6.5em; } .cell { display: inline-block; width: 2em; height: 2em; text-align: center; border: thin solid blue; box-sizing: border-box; /* 修正原错误属性名box-model */ vertical-align: top; line-height: 2; }
JavaScript
document.addEventListener('DOMContentLoaded', function () { const board = document.getElementById('board'); const resetBtn = document.getElementById('resetBtn'); const message = document.getElementById('message'); let currentPlayer = 'X'; let gameActive = true; let boardState = ['', '', '', '', '', '', '', '', '']; // 纯函数:仅判断胜负,不修改全局状态 function checkWinner(board) { const winConditions = [ [0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6], ]; for (let condition of winConditions) { const [a, b, c] = condition; if (board[a] !== '' && board[a] === board[b] && board[a] === board[c]) { return board[a]; } } if (!board.includes('')) { return 'tie'; } return null; } function makeMove(index) { if (boardState[index] === '' && gameActive) { boardState[index] = currentPlayer; renderBoard(); // 传入当前棋盘状态并处理结果 const winner = checkWinner(boardState); if (winner) { gameActive = false; message.innerText = winner === 'tie' ? '平局!' : `${winner} 获胜!`; return; } currentPlayer = currentPlayer === 'X' ? 'O' : 'X'; if (currentPlayer === 'O' && gameActive) { makeComputerMove(); } } } function makeComputerMove() { let bestScore = -Infinity; let bestMove; for (let i = 0; i < boardState.length; i++) { if (boardState[i] === '') { boardState[i] = 'O'; let score = minimax(boardState.slice(), 0, false); boardState[i] = ''; if (score > bestScore) { bestScore = score; bestMove = i; } } } makeMove(bestMove); } function minimax(board, depth, isMaximizing) { const result = checkWinner(board); const scores = { X: -10, O: 10, tie: 0, }; if (result !== null) { return scores[result]; } if (isMaximizing) { let bestScore = -Infinity; for (let i = 0; i < board.length; i++) { if (board[i] === '') { board[i] = 'O'; let score = minimax(board.slice(), depth + 1, false); board[i] = ''; bestScore = Math.max(score, bestScore); } } return bestScore; } else { let bestScore = Infinity; for (let i = 0; i < board.length; i++) { if (board[i] === '') { board[i] = 'X'; let score = minimax(board.slice(), depth + 1, true); board[i] = ''; bestScore = Math.min(score, bestScore); } } return bestScore; } } function renderBoard() { board.innerHTML = ''; boardState.forEach((cell, index) => { const cellElement = document.createElement('div'); cellElement.classList.add('cell'); cellElement.innerText = cell; cellElement.addEventListener('click', () => makeMove(index)); board.appendChild(cellElement); }); } function resetBoard() { currentPlayer = 'X'; gameActive = true; boardState = ['', '', '', '', '', '', '', '', '']; renderBoard(); message.innerText = ''; } resetBtn.addEventListener('click', resetBoard); renderBoard(); });
关键修正点
- 修复参数缺失问题:在
makeMove中调用checkWinner时传入boardState,确保函数获取正确的棋盘状态。 - 分离纯函数与状态修改:将
checkWinner改为纯函数,仅返回胜负结果,不在函数内修改全局gameActive,而是在主逻辑中根据返回结果处理游戏状态和提示消息,避免递归调用干扰全局状态。 - 修正CSS属性错误:将原CSS中的
box-model改为正确的box-sizing,确保单元格边框不会超出设定尺寸。 - 优化变量作用域:将
scores对象移至minimax函数内部,减少全局变量污染。
内容的提问来源于stack exchange,提问作者jing bing
相关产品推荐
相关产品推荐

