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

Minimax算法中未达终止状态即触发深度为0时的静态评估值设定问题

咱们一步步拆解你的问题——当前代码里有几个关键错误导致了你的困惑,同时我们需要为非终局局面修正静态评估逻辑,让Minimax算法能正常工作。

首先修正代码里的明显错误

1. getGameResult 的平局判断完全逻辑颠倒

你现在的平局判断代码逻辑完全反了:它会在只要有一个格子非空就返回-5,而不是所有格子填满才判定平局。正确的逻辑应该是遍历所有格子,确认没有空位才返回0(平局),否则说明游戏还能继续:

// 检查平局:所有格子都已填满
bool isBoardFull = true;
for (int i = 0; i < BOARD_SIZE; i++) {
    for (int j = 0; j < BOARD_SIZE; j++) {
        if (board[i][j] == FieldStatus::EMPTY) {
            isBoardFull = false;
            break;
        }
    }
    if (!isBoardFull) break;
}
if (isBoardFull) return 0; // 平局

2. Minimax 的终止条件错误

你当前的终止条件是 if (depth == 0 && isGameOver()),这意味着只有当深度耗尽且游戏结束时才返回结果,但实际上Minimax的终止条件应该是任意一个条件满足就返回:要么游戏结束(不管深度),要么深度耗尽(不管游戏是否结束)。

核心问题:深度耗尽但游戏未结束时返回什么?

答案是:返回一个反映当前局面优势的静态评估值,而不是固定的-1/1/0。你的原函数只处理了终局情况,现在需要扩展它,让它能给非终局局面打分——分数越高,对最大化玩家(Cross)越有利;分数越低,对最小化玩家(Circle)越有利。

怎么设计静态评估函数?

以四子棋为例,我们可以统计双方的潜在获胜机会,给不同的局面分配权重:

  • Cross有一个三连+一个空位(下一步就能赢):极高价值,给+10分
  • Cross有一个两连+两个空位:中等价值,给+2分
  • 反过来,Circle有三连+空位:给-10分;两连+空位给-2分
  • 其他局面根据棋子分布调整分数

重命名原getGameResult为evaluateBoard,扩展后的完整代码示例:

int evaluateBoard() {
    // 先检查是否有玩家获胜(保留你原来的逻辑)
    // 检查竖直线
    for (int i = 0; i <= BOARD_SIZE - 4; i++) {
        for (int j = 0; j < BOARD_SIZE; j++) {
            if (board[i][j] == FieldStatus::CIRCLE && board[i+1][j] == FieldStatus::CIRCLE && 
                board[i+2][j] == FieldStatus::CIRCLE && board[i+3][j] == FieldStatus::CIRCLE) {
                return -1;
            } else if (board[i][j] == FieldStatus::CROSS && board[i+1][j] == FieldStatus::CROSS && 
                       board[i+2][j] == FieldStatus::CROSS && board[i+3][j] == FieldStatus::CROSS) {
                return 1;
            }
        }
    }
    // 检查水平线
    for (int i = 0; i < BOARD_SIZE; i++) {
        for (int j = 0; j <= BOARD_SIZE - 4; j++) {
            if (board[i][j] == FieldStatus::CIRCLE && board[i][j+1] == FieldStatus::CIRCLE && 
                board[i][j+2] == FieldStatus::CIRCLE && board[i][j+3] == FieldStatus::CIRCLE) {
                return -1;
            } else if (board[i][j] == FieldStatus::CROSS && board[i][j+1] == FieldStatus::CROSS && 
                       board[i][j+2] == FieldStatus::CROSS && board[i][j+3] == FieldStatus::CROSS) {
                return 1;
            }
        }
    }
    // 检查右对角线
    for (int i = 0; i <= BOARD_SIZE - 4; i++) {
        for (int j = 0; j <= BOARD_SIZE - 4; j++) {
            if (board[i][j] == FieldStatus::CIRCLE && board[i+1][j+1] == FieldStatus::CIRCLE && 
                board[i+2][j+2] == FieldStatus::CIRCLE && board[i+3][j+3] == FieldStatus::CIRCLE) {
                return -1;
            } else if (board[i][j] == FieldStatus::CROSS && board[i+1][j+1] == FieldStatus::CROSS && 
                       board[i+2][j+2] == FieldStatus::CROSS && board[i+3][j+3] == FieldStatus::CROSS) {
                return 1;
            }
        }
    }
    // 修正左对角线检查逻辑
    for (int i = 3; i < BOARD_SIZE; i++) {
        for (int j = 0; j <= BOARD_SIZE - 4; j++) {
            if (board[i][j] == FieldStatus::CIRCLE && board[i-1][j+1] == FieldStatus::CIRCLE && 
                board[i-2][j+2] == FieldStatus::CIRCLE && board[i-3][j+3] == FieldStatus::CIRCLE) {
                return -1;
            } else if (board[i][j] == FieldStatus::CROSS && board[i-1][j+1] == FieldStatus::CROSS && 
                       board[i-2][j+2] == FieldStatus::CROSS && board[i-3][j+3] == FieldStatus::CROSS) {
                return 1;
            }
        }
    }
    // 检查平局(修正后的逻辑)
    bool isBoardFull = true;
    for (int i = 0; i < BOARD_SIZE; i++) {
        for (int j = 0; j < BOARD_SIZE; j++) {
            if (board[i][j] == FieldStatus::EMPTY) {
                isBoardFull = false;
                break;
            }
        }
        if (!isBoardFull) break;
    }
    if (isBoardFull) return 0;

    // 非终局,计算静态评估分
    int crossScore = 0;
    int circleScore = 0;

    // 评估所有竖线的4格窗口
    for (int i = 0; i <= BOARD_SIZE - 4; i++) {
        for (int j = 0; j < BOARD_SIZE; j++) {
            int crossCnt = 0, circleCnt = 0, emptyCnt = 0;
            for (int k = 0; k < 4; k++) {
                FieldStatus s = board[i + k][j];
                if (s == FieldStatus::CROSS) crossCnt++;
                else if (s == FieldStatus::CIRCLE) circleCnt++;
                else emptyCnt++;
            }
            if (crossCnt == 3 && emptyCnt == 1) crossScore += 10;
            else if (crossCnt == 2 && emptyCnt == 2) crossScore += 2;
            if (circleCnt == 3 && emptyCnt == 1) circleScore += 10;
            else if (circleCnt == 2 && emptyCnt == 2) circleScore += 2;
        }
    }

    // 评估所有水平线的4格窗口
    for (int i = 0; i < BOARD_SIZE; i++) {
        for (int j = 0; j <= BOARD_SIZE - 4; j++) {
            int crossCnt = 0, circleCnt = 0, emptyCnt = 0;
            for (int k = 0; k < 4; k++) {
                FieldStatus s = board[i][j + k];
                if (s == FieldStatus::CROSS) crossCnt++;
                else if (s == FieldStatus::CIRCLE) circleCnt++;
                else emptyCnt++;
            }
            if (crossCnt == 3 && emptyCnt == 1) crossScore += 10;
            else if (crossCnt == 2 && emptyCnt == 2) crossScore += 2;
            if (circleCnt == 3 && emptyCnt == 1) circleScore += 10;
            else if (circleCnt == 2 && emptyCnt == 2) circleScore += 2;
        }
    }

    // 评估右对角线的4格窗口
    for (int i = 0; i <= BOARD_SIZE - 4; i++) {
        for (int j = 0; j <= BOARD_SIZE - 4; j++) {
            int crossCnt = 0, circleCnt = 0, emptyCnt = 0;
            for (int k = 0; k < 4; k++) {
                FieldStatus s = board[i + k][j + k];
                if (s == FieldStatus::CROSS) crossCnt++;
                else if (s == FieldStatus::CIRCLE) circleCnt++;
                else emptyCnt++;
            }
            if (crossCnt == 3 && emptyCnt == 1) crossScore += 10;
            else if (crossCnt == 2 && emptyCnt == 2) crossScore += 2;
            if (circleCnt == 3 && emptyCnt == 1) circleScore += 10;
            else if (circleCnt == 2 && emptyCnt == 2) circleScore += 2;
        }
    }

    // 评估左对角线的4格窗口
    for (int i = 3; i < BOARD_SIZE; i++) {
        for (int j = 0; j <= BOARD_SIZE - 4; j++) {
            int crossCnt = 0, circleCnt = 0, emptyCnt = 0;
            for (int k = 0; k < 4; k++) {
                FieldStatus s = board[i - k][j + k];
                if (s == FieldStatus::CROSS) crossCnt++;
                else if (s == FieldStatus::CIRCLE) circleCnt++;
                else emptyCnt++;
            }
            if (crossCnt == 3 && emptyCnt == 1) crossScore += 10;
            else if (crossCnt == 2 && emptyCnt == 2) crossScore += 2;
            if (circleCnt == 3 && emptyCnt == 1) circleScore += 10;
            else if (circleCnt == 2 && emptyCnt == 2) circleScore += 2;
        }
    }

    // 返回Cross的优势减去Circle的优势
    return crossScore - circleScore;
}

修正后的Minimax函数

int minimax(int depth, bool isCross) {
    int eval = evaluateBoard();

    // 终止条件:深度耗尽,或者游戏已结束(获胜/平局)
    if (depth == 0 || abs(eval) == 1 || eval == 0) {
        return eval;
    }

    // 最大化玩家(Cross)逻辑
    if (isCross) {
        int bestScore = INT_MIN;
        for (int i = 0; i < BOARD_SIZE; i++) {
            for (int j = 0; j < BOARD_SIZE; j++) {
                if (board[i][j] == FieldStatus::EMPTY) {
                    board[i][j] = FieldStatus::CROSS;
                    int currentScore = minimax(depth - 1, false);
                    board[i][j] = FieldStatus::EMPTY;
                    bestScore = max(bestScore, currentScore);
                }
            }
        }
        return bestScore;
    } else {
        // 最小化玩家(Circle)逻辑
        int bestScore = INT_MAX;
        for (int i = 0; i < BOARD_SIZE; i++) {
            for (int j = 0; j < BOARD_SIZE; j++) {
                if (board[i][j] == FieldStatus::EMPTY) {
                    board[i][j] = FieldStatus::CIRCLE;
                    int currentScore = minimax(depth - 1, true);
                    board[i][j] = FieldStatus::EMPTY;
                    bestScore = min(bestScore, currentScore);
                }
            }
        }
        return bestScore;
    }
}
为什么这样做能解决问题?
  • 当深度耗尽时,返回的静态评估值能准确反映当前局面的优劣,Minimax的最大化/最小化逻辑可以基于这个值选择最优的下一步,不会被固定值干扰。
  • 修正后的终止条件确保无论游戏是否结束,只要深度到0就返回评估结果,符合Minimax的设计逻辑。
  • 修复了平局判断和左对角线检查的错误,避免了不必要的逻辑混乱。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 09:12:32