在极小化极大树的特定深度中计算移动得分

15

我用C语言实现了一个国际象棋游戏,使用以下结构体:

move - 表示在字符棋盘[8][8](国际象棋棋盘)上从(a,b)移动到(c,d)的动作

moves - 是一系列带有头和尾的移动的链表。

变量: playing_color为'W'或'B'。 minimax_depth是之前设置的极小极大深度。

这里是我的具有alpha-beta剪枝的Minimax函数的代码以及getMoveScore函数的代码。getMoveScore函数应该返回在设定的Minimax树的某个minimax_depth级别中移动的得分。

同样,我正在使用getBestMoves函数,我也将在此处列出它,它基本上在Minimax算法中找到最佳移动并将其保存到全局变量中,以便稍后使用。

我必须补充说明,所有列在此处的三个函数中的函数都正常工作并经过测试,因此问题要么是alphabetaMax算法的逻辑问题,要么是getBestMoves / getMoveScore的实现问题。

主要问题在于,当我在N级别获得最佳移动(由于一些原因也未正确计算),然后使用getMoveScore函数在相同级别上检查它们的得分时,我得到了不匹配的得分。我花了数小时来调试此问题,但无法找到错误,希望有人可以给我提供一个找到问题的提示。

代码如下:

/*
* Getting best possible moves for the playing color with the minimax algorithm
*/
moves* getBestMoves(char playing_color){
    //Allocate memory for the best_moves which is a global variable to fill it in   a minimax algorithm//
    best_moves = calloc(1, sizeof(moves));
    //Call an alpha-beta pruned minimax to compute the best moves//
    alphabeta(playing_color, board, minimax_depth, INT_MIN, INT_MAX, 1);
    return best_moves;
}

/*
* Getting the score of a given move for a current player
*/
int getMoveScore(char playing_color, move* curr_move){
    //Allocate memory for best_moves although its not used so its just freed    later//
    best_moves = calloc(1, sizeof(moves));
    int score;
    char board_cpy[BOARD_SIZE][BOARD_SIZE];
    //Copying a a current board and making a move on that board which score I   want to compute//
    boardCopy(board, board_cpy);
    actualBoardUpdate(curr_move, board_cpy, playing_color);
    //Calling the alphabeta Minimax now with the opposite color , a board after     a given move and as a minimizing player, because basicly I made my move so  its now the opponents turn and he is the minimizing player//
    score = alphabeta(OppositeColor(playing_color), board_cpy, minimax_depth, INT_MIN, INT_MAX, 0);
    freeMoves(best_moves->head);
    free(best_moves);
    return score;
}

/*
* Minimax function - finding the score of the best move possible from the input board
*/
int alphabeta(char playing_color, char curr_board[BOARD_SIZE][BOARD_SIZE], int depth,int alpha,int beta, int maximizing) {
    if (depth == 0){
        //If I'm at depth 0 I'm evaluating the current board with my scoring            function//
        return scoringFunc(curr_board, playing_color);
    }
    int score;
    int max_score;
    char board_cpy[BOARD_SIZE][BOARD_SIZE];
    //I'm getting all the possible legal moves for the playing color//
    moves * all_moves = getMoves(playing_color, curr_board);
    move* curr_move = all_moves->head;
    //If its terminating move I'm evaluating board as well, its separate from depth == 0 because    only here I want to free memory//
    if (curr_move == NULL){
        free(all_moves);
        return scoringFunc(curr_board,playing_color);
    }
    //If maximizing player is playing//
    if (maximizing) {
        score = INT_MIN;
        max_score = score;
        while (curr_move != NULL){
            //Make the move and call alphabeta with the current board               after the move for opposite color and !maximizing player//
            boardCopy(curr_board, board_cpy);
            actualBoardUpdate(curr_move, board_cpy, playing_color);
            score = alphabeta(OppositeColor(playing_color), board_cpy, depth - 1,alpha,beta, !maximizing);
            
            alpha = MAX(alpha, score);
            if (beta <= alpha){
                break;
            }
            //If I'm at the maximum depth I want to get current player              best moves//
            if (depth == minimax_depth){
                move* best_move;
                //If I found a move with a score that is bigger then                    the max score, I will free all previous moves and                   append him, and update the max_score//
                if (score > max_score){
                    max_score = score;
                    freeMoves(best_moves->head);
                    free(best_moves);
                    best_moves = calloc(1, sizeof(moves));
                    best_move = copyMove(curr_move);
                    concatMoves(best_moves, best_move);
                }
                //If I have found a move with the same score and want                   to concatenate it to a list of best moves//
                else if (score == max_score){
                    best_move = copyMove(curr_move);
                    concatMoves(best_moves, best_move);
                }
                
            }
            //Move to the next move//
            curr_move = curr_move->next;
        }
        freeMoves(all_moves->head);
        free(all_moves);
        return alpha;
    }
    else {
        //The same as maximizing just for a minimizing player and I dont want       to look for best moves here because I dont want to minimize my          outcome//
        score = INT_MAX;
        while (curr_move != NULL){
            boardCopy(curr_board, board_cpy);
            actualBoardUpdate(curr_move, board_cpy, playing_color);
            score = alphabeta(OppositeColor(playing_color), board_cpy, depth - 1,alpha,beta, !maximizing);
            beta = MIN(beta, score);
            if (beta <= alpha){
                break;
            }
            curr_move = curr_move->next;
        }
        freeMoves(all_moves->head);
        free(all_moves);
        return beta;
    }
}

正如Eugene指出的那样 - 我在这里添加一个示例:http://imageshack.com/a/img910/4643/fmQvlm.png

我目前执白,只有国王-k和皇后-q,对方执黑,有国王-K和车-R。显然,在这种情况下,我的最佳着法是吃掉车或至少使对方进入被将军状态。棋子的移动已经过测试,并且运行良好。然而,当我在深度为3时调用get_best_moves函数时,我会得到许多不必要的移动和负分数。也许现在更清楚了。谢谢!


没有最小可重现示例,没有期望行为,也没有实际行为。我们与此有很少的关系。 - Eugene Sh.
@EugeneSh。我现在添加了一个详细的示例,我需要再添加什么吗? - Evgeny
1
@EvgenyA.:在其他地方建设性合作,我给你点赞。你比我更需要它。;-) - DevSolar
1个回答

0

在不调试整个代码的情况下,至少有一个问题是您的scoreverification可能适用于minimax算法,但不适用于Alpha-Beta算法。存在以下问题:

getMoveScore()函数必须从打开的AB窗口开始。

然而,在getBestMoves()中,使用已经关闭的AB窗口调用getMoveScore()。

因此,在getBestMoves的情况下,可能会剪枝一些分支,这些分支在getMoveScore()中没有被剪枝,因此分数不准确,这就是(或者至少是)这些值不同的原因。


我不太明白你所说的“closed AB Window”是什么意思,你的意思是我应该在getMoveScore中使用OppositeColor调用alphabeta函数作为最大化玩家吗?就我理解而言,在getMoveScore中我会进行一次移动,因此我应该为对手调用alphabeta,但他应该最小化还是最大化呢? - Evgeny
好的,我明白了。你所说的打开AB窗口是什么意思?我应该尝试哪些值?或者我如何计算我需要的值?顺便说一句,getBestMoves不会调用getMoveScore,它们是独立的。 - Evgeny
好的,谢谢你提醒。我在学习计算机科学,这是我们课程中的一个项目。 - Evgeny
你有没有什么线索,为什么最佳的移动没有被正确计算? - Evgeny
还没有...我会再看一下。 - xXliolauXx
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接