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
相关产品推荐
相关产品推荐

