井字棋Negamax算法输出错误求排查:已实现Minimax但走法异常
井字棋Negamax算法错误排查与修复
核心问题分析
你的代码存在两个关键逻辑错误,导致Negamax输出错误走法:
终止条件的得分处理错误
Negamax的核心是递归时通过对得分取反来切换玩家视角,因此终止节点的得分不需要再根据maximizingPlayer取反。你的代码里在游戏结束时返回maxmizingPlayer? score : -score,这会导致得分视角混乱,最终计算出错误的最优解。Alpha-Beta剪枝的alpha更新逻辑错误
当前代码用bestMove.score更新alpha,但正确的做法应该是用当前遍历的move.score来更新,因为bestMove是累计的最优值,而alpha需要反映当前分支能获得的最大下界,用当前move的得分才符合剪枝逻辑。
修正后的代码
static negamax(board, alpha, beta, maximizingPlayer) { const emptyCells = this.getEmptyCells(board); if (this.isGameOver(board) || emptyCells.length === 0) { // 直接返回评估得分,无需根据玩家取反 return { score: this.evaluate(board) }; } let bestMove = { score: -Infinity }; for (let i = 0; i < emptyCells.length; ++i) { const { x, y } = emptyCells[i]; board[y][x] = maximizingPlayer ? this.mySymbol : this.opSymbol; // Negamax递归:取反得分和alpha/beta值,切换玩家 const childMove = this.negamax(board, -beta, -alpha, !maximizingPlayer); const move = { score: -childMove.score, x, y }; board[y][x] = this.emptySymbol; // 更新最优走法 if (move.score > bestMove.score) { bestMove = move; } // 用当前move的得分更新alpha,而非bestMove的得分 alpha = Math.max(alpha, move.score); if (beta <= alpha) { break; } } return bestMove; } static evaluate(board) { if (this.isWinning(board, this.mySymbol)) { // 修正原代码拼写错误:isWining → isWinning return Infinity; } if (this.isWinning(board, this.opSymbol)) { return -Infinity; } return 0; }
额外注意点
- 原代码中
isWining是拼写错误,修正为isWinning,避免函数调用失败。 - 递归调用时直接获取子节点的返回值再取反得分,代码结构更清晰。
内容的提问来源于stack exchange,提问作者saltdream
相关产品推荐
相关产品推荐

