井字棋Minimax算法JavaScript实现异常:AI无法选最优落子
井字棋Minimax算法AI无法智能决策问题
我花了好几个小时给井字棋实现Minimax算法作为AI,但AI根本不会做智能决策,只会选第一个可行的落子位置。这是我第一次实现这类算法,参考了GeeksforGeeks的文章和YouTube视频。其中'O'是最大化玩家(AI),'X'是最小化玩家(人类)。findBestMove函数接收棋盘数组,返回最优落子的索引,用来更新网页上的可视化棋盘。代码如下:
const check = (n1, n2, n3) => { if (n1 === '') return; if (n1 === n2 && n2 === n3) { value = n1; } } const checkResult = () => { // Check all possible win scenarios check(board[0][0], board[0][1], board[0][2]); check(board[1][0], board[1][1], board[1][2]); check(board[2][0], board[2][1], board[2][2]); check(board[0][0], board[1][0], board[2][0]); check(board[0][1], board[1][1], board[2][1]); check(board[0][2], board[1][2], board[2][2]); check(board[0][0], board[1][1], board[2][2]); check(board[0][2], board[1][1], board[2][0]); if (value === 'X') { return -10; } else if (value === 'O') { return 10; } } function findBestMove(board) { let bestMove = {}; let bestVal = -Infinity; for (let i = 0; i < 3; i++) { for (let j = 0; j < 3; j++) { if (board[i][j] === '') { board[i][j] = 'O'; let moveVal = minimax(board, 0, false); board[i][j] = ''; if (moveVal > bestVal) { bestVal = moveVal; bestMove = { i, j }; } } } } return bestMove; } function minimax(board, depth, maxPlayer) { let score = GameBoard.checkResult(); if (!!score) { if (score < 0) { return score + depth; } else { return score - depth; } } if (!isMovesLeft(board)) { return 0; } if (maxPlayer) { let maxEval = -Infinity; for (let i = 0; i < 3; i++) { for (let j = 0; j < 3; j++) { if (board[i][j] === '') { board[i][j] = 'O'; let eval = minimax(board, depth + 1, false); board[i][j] = ''; maxEval = Math.max(maxEval, eval); console.log(maxEval + ' ' + eval); } } } return maxEval; } else { let minEval = Infinity; for (let i = 0; i < 3; i++) { for (let j = 0; j < 3; j++) { if (board[i][j] === '') { board[i][j] = 'X'; let eval = minimax(board, depth + 1, true); board[i][j] = ''; minEval = Math.min(minEval, eval); } } } return minEval; } } function isMovesLeft(board) { for (let i = 0; i < 3; i++) { for (let j = 0; j < 3; j++) { if (board[i][j] === '') { return true; } } } return false; }
问题根源
你的代码存在三个核心错误,导致Minimax算法无法正确评估局面:
- 全局变量
value污染:check函数使用未声明的全局变量value,每次调用checkResult时不会重置该变量,残留的旧值会导致获胜判断完全错误。 checkResult上下文错误:函数直接引用外部全局board变量,而非Minimax递归中传入的模拟棋盘,导致评估的始终是原始棋盘状态。checkResult返回逻辑缺失:无获胜情况时函数未返回值,虽不影响布尔判断,但结合全局变量问题会进一步加剧评估混乱。
修复后的代码
// 重构check函数,直接返回获胜者或null,避免全局变量 const check = (n1, n2, n3) => { if (n1 === '') return null; return n1 === n2 && n2 === n3 ? n1 : null; }; // 重构checkResult,接收棋盘参数,遍历所有获胜模式 const checkResult = (board) => { const winPatterns = [ [0,0, 0,1, 0,2], [1,0, 1,1, 1,2], [2,0, 2,1, 2,2], [0,0, 1,0, 2,0], [0,1, 1,1, 2,1], [0,2, 1,2, 2,2], [0,0, 1,1, 2,2], [0,2, 1,1, 2,0] ]; for (const [x1,y1,x2,y2,x3,y3] of winPatterns) { const winner = check(board[x1][y1], board[x2][y2], board[x3][y3]); if (winner) { return winner === 'X' ? -10 : 10; } } return null; }; function findBestMove(board) { let bestMove = {}; let bestVal = -Infinity; for (let i = 0; i < 3; i++) { for (let j = 0; j < 3; j++) { if (board[i][j] === '') { board[i][j] = 'O'; const moveVal = minimax(board, 0, false); board[i][j] = ''; if (moveVal > bestVal) { bestVal = moveVal; bestMove = { i, j }; } } } } return bestMove; } function minimax(board, depth, maxPlayer) { const score = checkResult(board); if (score !== null) { // 深度调整分数:优先选择最快获胜/最慢失败的路径 return score < 0 ? score + depth : score - depth; } if (!isMovesLeft(board)) { return 0; // 平局 } if (maxPlayer) { let maxEval = -Infinity; for (let i = 0; i < 3; i++) { for (let j = 0; j < 3; j++) { if (board[i][j] === '') { board[i][j] = 'O'; const eval = minimax(board, depth + 1, false); board[i][j] = ''; maxEval = Math.max(maxEval, eval); } } } return maxEval; } else { let minEval = Infinity; for (let i = 0; i < 3; i++) { for (let j = 0; j < 3; j++) { if (board[i][j] === '') { board[i][j] = 'X'; const eval = minimax(board, depth + 1, true); board[i][j] = ''; minEval = Math.min(minEval, eval); } } } return minEval; } } function isMovesLeft(board) { for (let i = 0; i < 3; i++) { for (let j = 0; j < 3; j++) { if (board[i][j] === '') { return true; } } } return false; }
修复说明
- 移除全局变量:通过让
check函数直接返回结果,彻底避免全局变量污染问题。 - 绑定棋盘上下文:
checkResult现在接收传入的棋盘参数,确保递归中每个模拟局面都被正确评估。 - 优化获胜判断逻辑:用数组存储所有获胜坐标模式,代码更清晰易维护。
- 修正Minimax调用:将
GameBoard.checkResult()改为checkResult(board),确保使用当前递归的棋盘状态。
修改后,AI会正确执行Minimax算法,优先选择能直接获胜的位置,其次阻止人类获胜,最终实现智能落子。
内容的提问来源于stack exchange,提问作者Zack
相关产品推荐
相关产品推荐

