You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

井字棋Minimax AI后手落子异常问题求助

问题分析与修复方案

核心问题定位

AI后手时落子异常,主要源于以下几个关键逻辑错误:

1. findBestMove中后手AI的价值比较逻辑错误

当AI为aiWeapon=2(后手,对应Minimax的极小值玩家)时,你仍用moveValue > bestValue判断最优解,但极小值玩家的目标是让评估分数尽可能小(对应玩家无法获胜),因此应改为moveValue < bestValue,且初始bestValue要设为Infinity而非-Infinity。

2. isMovesLeft函数未传入目标棋盘参数

当前函数直接依赖全局board变量,而Minimax递归时会临时修改棋盘副本(虽有回溯操作),依赖全局变量会导致递归中的可用落子判断错误,必须将当前棋盘作为参数传入。

3. bestMove初始化方式不规范

你将bestMove赋值为makeMove函数后直接添加属性,这不符合JS对象使用规范,应直接初始化一个存储落子位置的普通对象。

4. Minimax未做深度优化(可选但推荐)

原评估分数直接返回±10,未结合递归深度调整,会导致AI无法优先选择更快获胜、或更晚失败的路径。


修复后的完整代码

修复后的evaluateMove函数

function evaluateMove(board) {
    // 检查行
    for (let row = 0; row < board.length; row += 1) {
        if (board[row][0] === board[row][1] && board[row][1] === board[row][2]) {
            if (board[row][0] === 1) return +10;
            if (board[row][0] === 2) return -10;
        }
    }

    // 检查列
    for (let column = 0; column < board.length; column += 1) {
        if (board[0][column] === board[1][column] && board[1][column] === board[2][column]) {
            if (board[0][column] === 1) return +10;
            if (board[0][column] === 2) return -10;
        }
    }

    // 检查对角线
    if (board[0][0] === board[1][1] && board[1][1] === board[2][2]) {
        if (board[0][0] === 1) return +10;
        if (board[0][0] === 2) return -10;
    }
    if (board[0][2] === board[1][1] && board[1][1] === board[2][0]) {
        if (board[0][2] === 1) return +10;
        if (board[0][2] === 2) return -10;
    }
    return 0;
}

修复后的minimax函数(添加深度修正)

function minimax(board, depth, isMaximizer) {
    const score = evaluateMove(board);

    // AI获胜,返回分数并减去深度(优先选择更快获胜的路径)
    if (score === 10) return score - depth;
    // 玩家获胜,返回分数并加上深度(优先选择更晚失败的路径)
    if (score === -10) return score + depth;
    // 平局
    if (!isMovesLeft(board)) return 0;

    if (isMaximizer) {
        let best = -1000;
        for (let row = 0; row < board.length; row += 1) {
            for (let column = 0; column < board.length; column += 1) {
                if (board[row][column] === 0) {
                    board[row][column] = 1;
                    best = Math.max(best, minimax(board, depth + 1, false));
                    board[row][column] = 0; // 回溯
                }
            }
        }
        return best;
    } else {
        let best = 1000;
        for (let row = 0; row < board.length; row += 1) {
            for (let column = 0; column < board.length; column += 1) {
                if (board[row][column] === 0) {
                    board[row][column] = 2;
                    best = Math.min(best, minimax(board, depth + 1, true));
                    board[row][column] = 0; // 回溯
                }
            }
        }
        return best;
    }
}

修复后的findBestMove函数

function findBestMove(board) {
    let bestValue;
    const bestMove = { row: -1, column: -1 };

    // 根据AI角色初始化最优值
    if (aiWeapon === 1) {
        bestValue = -Infinity;
    } else {
        bestValue = Infinity;
    }

    for (let row = 0; row < board.length; row += 1) {
        for (let column = 0; column < board.length; column += 1) {
            if (board[row][column] === 0) {
                board[row][column] = aiWeapon;
                // 根据AI角色调用Minimax:先手是极大值玩家,后手是极小值玩家
                const moveValue = minimax(board, 0, aiWeapon === 1);
                board[row][column] = 0; // 回溯

                // 不同角色的最优值判断逻辑
                if (aiWeapon === 1) {
                    if (moveValue > bestValue) {
                        bestMove.row = row;
                        bestMove.column = column;
                        bestValue = moveValue;
                    }
                } else {
                    if (moveValue < bestValue) {
                        bestMove.row = row;
                        bestMove.column = column;
                        bestValue = moveValue;
                    }
                }
            }
        }
    }
    return bestMove;
}

修复后的isMovesLeft函数

function isMovesLeft(board) {
    // 遍历所有格子,检查是否有空闲位置
    for (let row = 0; row < board.length; row += 1) {
        for (let column = 0; column < board.length; column += 1) {
            if (board[row][column] === 0) return true;
        }
    }
    return false;
}

关键修复说明

  1. 后手AI逻辑修正:极小值玩家需寻找最小评估值,确保AI会优先阻止玩家获胜,而非盲目按顺序落子。
  2. 棋盘参数化:让isMovesLeft依赖传入的当前棋盘,避免全局变量导致的递归逻辑混乱。
  3. 对象初始化规范:使用普通对象存储落子位置,避免函数属性的不规范用法。
  4. 深度优化:通过调整分数的深度修正,让AI选择更高效的胜负路径。

内容的提问来源于stack exchange,提问作者kcolrehs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 22:12:33