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

C语言黑白棋AI持续选择无效(0,0)位置故障排查

控制台黑白棋AI无效落子问题排查与解决

问题现象

AI回合时,程序无限输出以下内容,陷入无效落子循环:

Computer's turn (Player B).
Computer chooses row 0, column 0.
Invalid move. Try again.

原因分析

1. isValidMove函数边界检查顺序错误

函数先检查目标位置是否为空,再判断坐标是否在棋盘范围内。如果传入非法坐标(如-1,-1),会先访问board[row][col]触发未定义行为,导致函数返回错误结果,进而影响合法移动的判定。

2. getBestMove函数初始值设置不合理

  • maxScore初始值为-1,而评分矩阵中存在大量低于-1的分值(如-50、-20),导致这些合法移动无法被选中,bestRow和bestCol保持初始值-1。
  • 当AI无合法移动时,numMoves为0,循环不执行,bestRow和bestCol仍为-1,后续输出时会被转换为row+1=0、col+1=0,即无效的(0,0)位置。

3. isValidMove翻转逻辑冗余易出错

原代码的while循环条件与内部判断重复,可能导致合法移动的漏判。

解决方法

1. 修正isValidMove的边界检查顺序

先判断坐标合法性,再检查位置是否为空:

bool isValidMove(const char board[BOARD_SIZE][BOARD_SIZE], int row, int col, char currentPlayer) {
    // 先检查坐标是否在棋盘范围内
    if (row < 0 || row >= BOARD_SIZE || col < 0 || col >= BOARD_SIZE) {
        return false;
    }
    // 再检查目标位置是否为空
    if (board[row][col] != ' ') {
        return false;
    }

    // 剩余逻辑保持不变...
}

2. 优化getBestMove的初始值与无移动处理

  • 将maxScore初始化为最小整数,确保所有合法移动的评分都能被正确比较;
  • 在AI回合增加无合法移动的处理逻辑,直接跳过回合:

修改后的getBestMove:

#include <limits.h> // 需要引入该头文件获取INT_MIN

int* getBestMove(const char board[BOARD_SIZE][BOARD_SIZE], char currentPlayer, int moves[], int numMoves){
    int score[8][8] = {
        {100, -20, 10, 5, 5, 10, -20, 100},
        {-20, -50, -2, -2, -2, -2, -50, -20},
        {10, -2, -1, -1, -1, -1, -2, 10},
        {5, -2, -1, -1, -1, -1, -2, 5},
        {5, -2, -1, -1, -1, -1, -2, 5},
        {10, -2, -1, -1, -1, -1, -2, 10},
        {-20, -50, -2, -2, -2, -2, -50, -20},
        {100, -20, 10, 5, 5, 10, -20, 100}
    };

    int* bestMove = (int*)malloc(2 * sizeof(int));
    int maxScore = INT_MIN; // 初始化为整数最小值
    int bestRow = -1;
    int bestCol = -1;

    for (int i = 0; i < numMoves; i++) {
        int row = moves[i] / BOARD_SIZE;
        int col = moves[i] % BOARD_SIZE;

        if (!isValidMove(board, row, col, currentPlayer)) {
            continue;
        }

        int moveScore = score[row][col];

        if (moveScore > maxScore) {
            maxScore = moveScore;
            bestRow = row;
            bestCol = col;
        }
    }

    bestMove[0] = bestRow;
    bestMove[1] = bestCol;

    return bestMove;
}

在game_pvc的AI回合部分增加无移动处理:

// Computer player's turn
else {
    printf("Computer's turn (Player %c).\n", currentPlayer);

    int moves[BOARD_SIZE * BOARD_SIZE];
    int numMoves;
    listPossibleMoves(board, currentPlayer, moves, &numMoves);

    // 处理无合法移动的情况
    if (numMoves == 0) {
        printf("Computer has no valid moves. Skipping turn.\n");
        currentPlayer = (currentPlayer == 'W') ? 'B' : 'W';
        printf("Press Enter to continue...");
        getchar();
        getchar(); // 清除输入缓冲区的换行符
        continue;
    }

    int* bestMove = getBestMove(board, currentPlayer, moves, numMoves);
    row = bestMove[0];
    col = bestMove[1];
    free(bestMove);

    printf("Computer chooses row %d, column %d.\n", row + 1, col + 1);
}

3. 简化isValidMove的翻转逻辑

调整while循环逻辑,让判断更清晰:

// 检查相邻位置是否为对手棋子
if (r >= 0 && r < BOARD_SIZE && c >= 0 && c < BOARD_SIZE && board[r][c] != ' ' && board[r][c] != currentPlayer) {
    // 沿该方向继续查找己方棋子
    while (true) {
        r += deltaRow;
        c += deltaCol;
        // 出界或遇到空格,判定为无效
        if (r < 0 || r >= BOARD_SIZE || c < 0 || c >= BOARD_SIZE || board[r][c] == ' ') {
            break;
        }
        // 找到己方棋子,判定为有效移动
        if (board[r][c] == currentPlayer) {
            return true;
        }
        // 否则继续循环(当前位置仍为对手棋子)
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 17:42:06