极小化-极大化算法在井字游戏中的应用出现问题

我之前在这个论坛上发布了一个类似的问题,但由于旧帖子的内容有点长,而且我重写了我的算法,所以我开始了这个新帖子。旧帖子可以在这里找到。


所以我只是试图为我的井字游戏实现一个极小化-极大化算法,但结果证明这相当困难,即使在尝试了几天后,我仍然找不到错误。你可以在下面找到我的代码。首先,我有一些定义、类型定义和声明:

typedef signed char s8;typedef unsigned char u8;typedef s8 score;#define STATE_00    getBoardState(0, 0)#define STATE_01    getBoardState(0, 1)#define STATE_02    getBoardState(0, 2)#define STATE_10    getBoardState(1, 0)#define STATE_11    getBoardState(1, 1)#define STATE_12    getBoardState(1, 2)#define STATE_20    getBoardState(2, 0)#define STATE_21    getBoardState(2, 1)#define STATE_22    getBoardState(2, 2)typedef enum {    EPlayerX = 1,    EPlayerO} EPlayer;typedef enum {    EMinimizing = 0,    EMaximizing} EMinMax;static u8 g_boardState[3][3] = {    {0, 0, 0,},    {0, 0, 0,},    {0, 0, 0,},};

接下来是一些函数:

u8 getBoardState(u8 row, u8 column);EPlayer isWon(void){    EPlayer winningBoards[8][3] = {        {STATE_00, STATE_01, STATE_02},        {STATE_10, STATE_11, STATE_12},        {STATE_20, STATE_21, STATE_22},        {STATE_00, STATE_10, STATE_20},        {STATE_01, STATE_11, STATE_21},        {STATE_02, STATE_12, STATE_22},        {STATE_00, STATE_11, STATE_22},        {STATE_20, STATE_11, STATE_02},    };    u8 i;    for(i=0; i<8; i++){        if( (winningBoards[i][0] != 0) &&            (winningBoards[i][0] == winningBoards[i][1]) &&            (winningBoards[i][0] == winningBoards[i][2])){                return winningBoards[i][0];        }    }    return 0;}u8 getBoardState(u8 row, u8 column){    return g_boardState[row][column];}void setBoardState(u8 row, u8 column, u8 state){    g_boardState[row][column] = state;}u8 isDraw(void){    u8 i, j;    for(i=0; i<3; i++){        for(j=0; j<3; j++){            if(getBoardState(i, j) == 0){                return 0;            }        }    }    return 1;}void dumpTable(score table[3][3]){    int i, j;    for(i=0; i<3; i++) {        printf("\n");        for(j=0; j<3; j++){            printf("%6i ", table[i][j]);        }    }    printf("\n");}EPlayer playerSwitch(EPlayer player){    if(player == EPlayerO) return EPlayerX;    if(player == EPlayerX) return EPlayerO;    return 0;}EMinMax modeSwitch(EMinMax mode){    if(mode == EMaximizing) return EMinimizing;    if(mode == EMinimizing) return EMaximizing;    return 0;}

然后是实际的极小化-极大化算法,这里称为scoring

score scoring(EMinMax mode, EPlayer player, u8 depth){    score thisScore, tempScore;    if(mode == EMaximizing){        thisScore = -20;        if(isWon()) return 15-depth;    }    if(mode == EMinimizing){        thisScore = 20;        if(isWon()) return depth-15;    }    if(isDraw()){        return 0;    }    u8 i, j;    for(i=0; i<3; i++){        for(j=0; j<3; j++){            if(getBoardState(i, j) == 0){                setBoardState(i, j, player);                tempScore = scoring(modeSwitch(mode), playerSwitch(player), depth+1);                if((mode == EMaximizing) && (tempScore > thisScore)){                    thisScore = tempScore;                }                if((mode == EMinimizing) && (tempScore < thisScore)){                    thisScore = tempScore;                }                setBoardState(i, j, 0);            }        }    }    return thisScore;}

最后是一个打印分数表的函数以及main函数:

void printSocredBoards(EPlayer player){       score thisScore[3][3] = {        {STATE_00, STATE_01, STATE_02},        {STATE_10, STATE_11, STATE_12},        {STATE_20, STATE_21, STATE_22},    };    int i, j;    if((isWon() == 0) && (isDraw() == 0)){        for(i=0; i<3; i++){            for(j=0; j<3; j++){                if(getBoardState(i, j) == 0){                    setBoardState(i, j, player);                    thisScore[i][j] = scoring(EMaximizing, playerSwitch(player), 0);                    setBoardState(i, j, 0);                }            }        }    }    dumpTable(thisScore);}int main(int argc, char **argv){    printSocredBoards(EPlayerO);    return 0;}

据我所知,这个算法应该可以正常工作,但它却给我输出了无意义的结果:

 7      7      7  7      0      7  7      7      7 

我错过了什么?提前感谢任何帮助。


回答:

我认为问题出在scoring函数中的这段代码,你的案例与正确的返回值相反:

if(mode == EMaximizing){    thisScore = -20;    if(isWon()) return 15-depth;}if(mode == EMinimizing){    thisScore = 20;    if(isWon()) return depth-15;}

直观上,问题在于当scoring到达代码的这个点时,对isWon的调用是在评估前一个棋子放置的结果,而前一个棋子放置是用另一个mode选择的。

例如,当scoringEMaximizing模式调用,并且棋盘状态已经获胜时,这意味着EMinimizing模式的玩家在这个状态下获胜,返回的分数应该反映这一点(即应该为负数)。由于深度最大值为8,当mode == EMaximizing时,你的返回值总是正数,这不是你想要的。

当案例反转时,你的程序输出全是零,这看起来更合理,因为完美的玩家应该总是平局。我还测试了代码,在printScoredBoards函数的顶部添加了以下一行,以硬编码第一步棋到左上角:

setBoardState(0, 0, playerSwitch(player));

这产生了以下结果:

 0     10     10 10      0     10 10     10     10 

正确地识别出第二个玩家不能选择左上角,并且如果他们在开局时选择除中心位置之外的任何位置都会输。

Related Posts

L1-L2正则化的不同系数

我想对网络的权重同时应用L1和L2正则化。然而,我找不…

使用scikit-learn的无监督方法将列表分类成不同组别,有没有办法?

我有一系列实例,每个实例都有一份列表,代表它所遵循的不…

f1_score metric in lightgbm

我想使用自定义指标f1_score来训练一个lgb模型…

通过相关系数矩阵进行特征选择

我在测试不同的算法时,如逻辑回归、高斯朴素贝叶斯、随机…

可以将机器学习库用于流式输入和输出吗?

已关闭。此问题需要更加聚焦。目前不接受回答。 想要改进…

在TensorFlow中,queue.dequeue_up_to()方法的用途是什么?

我对这个方法感到非常困惑,特别是当我发现这个令人费解的…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注