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

Caro游戏Minimax与findBestMove函数异常修复求助

Caro游戏AI走棋异常问题修复求助

我使用Minimax函数和findBestMove函数为12×12的Caro(类井字棋)游戏AI计算走棋位置,但函数出现错误导致AI走棋异常(存在连线逻辑问题)。多次调整函数仍未定位问题,附上相关代码,希望能帮忙修复函数使其正常运行。

相关代码

全局变量定义

int x_score = 0, o_score = 0, x_count = 0, o_count = 0, x = 0, y = 0, depth=15, value = 0, pos_i = -1, pos_j = -1;
int board[size][size]{};
bool x_turn = true;
int scoreVal[size][size];

Minimax函数实现

int game::minimax(bool isMaxiPlayer, int depth, int alpha, int beta) {
    int val = 0;
    bool stop = false;
    if (depth == 0) return 0;
    int i = 0, j = 0;
    if (draw()) {
        return 0;
    }
    else if (win()) {
        if (!x_turn) {
            return -10-depth;
        }
        else {
            return 10+depth;
        }
    }
    //else if (depth == 0) return value;
    if (isMaxiPlayer) {
        int bestVal = -1000;
        for (i =0; i < 12 &&(!stop); ++i)
            for (j = 0; j < 12 &&(!stop); ++j)
                if (board[i][j] == 0) {
                    board[i][j] = 1;
                    val = minimax(false, depth - 1, alpha, beta);
                    board[i][j] = 0;
                    bestVal = max(bestVal, val);
                    alpha = max(alpha, bestVal);
                    if (beta <= alpha) {
                        stop = true;
                    }
                }
        return bestVal;
    }
    else {
        int bestVal = 1000;
        for (i = 0; i < 12 &&(!stop); ++i)
            for (j = 0; j < 12 &&(!stop); ++j)
                if (board[i][j] == 0) {
                    board[i][j] = 2;
                    val = minimax(true, depth - 1, alpha, beta);
                    board[i][j] = 0;
                    bestVal = min(bestVal, val);
                    beta = min(beta, bestVal);
                    if (beta <= alpha) {
                        stop = true;
                    }
                }
        return bestVal;
    }
}

findBestMove函数实现

void game::findBestMove(bool isMaxiPlayer, int& pos_i, int& pos_j) {
    int bestVal = -1000;
    for (int i = 0; i < 12; ++i) {
        for (int j = 0; j < 12; ++j) {
            //cout << board[i][j];
            if (board[i][j] == 0) {
                board[i][j] = 2;
                int val = minimax(false, depth, -1000, 1000);
                if (val > bestVal) {
                    bestVal = val;
                    pos_i = i;
                    pos_j = j;
                }
                board[i][j] = 0;
                //printf("%d ", i, j);
            }
        }
    }

}

问题定位与修复方案

1. 胜负判断依赖全局变量的逻辑错误

Minimax函数中,胜负判断的返回值依赖全局x_turn变量,但该变量记录的是真实游戏的当前回合,而非递归模拟中的玩家。递归模拟落子后,胜负对应的玩家应根据当前递归的落子方判断,而非全局变量。

修复代码:

else if (win()) {
    // 需实现getWinner()函数,返回1(X玩家)、2(O玩家)或0(无胜者)
    int winner = getWinner();
    if (winner == 1) {
        return 10 + depth; // Max玩家获胜,返回高分
    } else {
        return -10 - depth; // Min玩家获胜,返回低分
    }
}

2. findBestMove函数的玩家角色混淆

当前函数固定落子为2(O玩家),完全忽略了isMaxiPlayer参数,导致无论AI是Max还是Min玩家,都模拟O落子,逻辑完全错误。

修复代码:

void game::findBestMove(bool isMaxiPlayer, int& pos_i, int& pos_j) {
    int bestVal = isMaxiPlayer ? -1000 : 1000;
    pos_i = -1;
    pos_j = -1;
    for (int i = 0; i < 12; ++i) {
        for (int j = 0; j < 12; ++j) {
            if (board[i][j] == 0) {
                int player = isMaxiPlayer ? 1 : 2;
                board[i][j] = player;
                int val = minimax(!isMaxiPlayer, depth, -1000, 1000);
                board[i][j] = 0;
                
                if (isMaxiPlayer) {
                    if (val > bestVal) {
                        bestVal = val;
                        pos_i = i;
                        pos_j = j;
                    }
                } else {
                    if (val < bestVal) {
                        bestVal = val;
                        pos_i = i;
                        pos_j = j;
                    }
                }
            }
        }
    }
}

3. Alpha-Beta剪枝的stop逻辑错误

原代码中触发剪枝时直接设置stop = true,会终止整个双重循环,跳过后续可能的最优落子。正确的剪枝应只终止当前层级的后续遍历。

修复代码(以Max玩家分支为例):

if (isMaxiPlayer) {
    int bestVal = -1000;
    for (int i = 0; i < 12; ++i) {
        for (int j = 0; j < 12; ++j) {
            if (board[i][j] == 0) {
                board[i][j] = 1;
                val = minimax(false, depth - 1, alpha, beta);
                board[i][j] = 0;
                bestVal = max(bestVal, val);
                alpha = max(alpha, bestVal);
                if (beta <= alpha) {
                    break; // 终止当前列遍历
                }
            }
        }
        if (beta <= alpha) {
            break; // 终止当前行遍历
        }
    }
    return bestVal;
}

Min玩家分支同理修改,移除stop变量。

4. 深度为0时的评估函数缺失

原代码中depth == 0时直接返回0,没有对当前棋盘局势进行评估。对于12×12的Caro游戏,需要实现启发式评估函数,计算双方潜在连线的得分。

示例评估函数框架:

int evaluateBoard() {
    int score = 0;
    // 遍历所有行、列、对角线,计算双方的潜在连线得分
    // 例如:连续3个同色棋子得10分,连续4个得100分,即将连成5子得1000分等
    // 具体逻辑根据Caro游戏(通常5子连线获胜)规则实现
    return score;
}

修改Minimax中的深度判断:

if (depth == 0) {
    return evaluateBoard();
}

5. 全局变量depth的风险

建议避免使用全局变量depth,改为在findBestMove中显式传递深度参数,避免递归过程中出现不可预期的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 20:12:06