c++中井字游戏的AI问题

Issues with AI for a tic tac toe game in C++

本文关键字:AI 问题 游戏 中井 c++      更新时间:2023-10-16

所以我对我的井字游戏的AI有一些问题。AI是纯粹防御性的,所以它总是会阻碍你。它通常在我的第一种情况下起作用,例如,如果我播放左上角,然后播放中上角,它总是会播放右上方。在其他情况下,比如我玩两条对角线,可能会冻结游戏,或者允许我进行第二次回合。这些问题是在我执行了错误的智能AI之后才出现的。最初,这个程序有一个"愚蠢的人工智能",可以随机选择一些点,就像你在代码底部看到的那样。此外,我认为问题在于一些阻塞条件可能相互冲突并导致问题。我该如何解决这个问题?有关守则如下:坐标基于tic tac toe网格,其中左上角为(0,0),右下角为(2,2)

void Game::AIGetNextMoveRand()
{
    //top row
    if(GetSquareState(0,0) == O && GetSquareState(1,0) == O)
    {
        do
        {
            AIMoveX = 2;
            AIMoveY = 0; 
        }
            while(GetSquareState(AIMoveX,AIMoveY) != EMPTY);
    }
    else if(GetSquareState(2,0) == O && GetSquareState(1,0) == O)
    {
        do
        {
            AIMoveX = 0;
            AIMoveY = 0;
        }
            while(GetSquareState(AIMoveX,AIMoveY) != EMPTY);
    }
    //middle row
    else if(GetSquareState(0,1) == O && GetSquareState(1,1) == O)
    {
        do
        {
        AIMoveX = 2;
        AIMoveY = 1;
        }
        while(GetSquareState(AIMoveX,AIMoveY) != EMPTY);
    }
    else if(GetSquareState(2,1) == O && GetSquareState(1,1) == O)
    {
        do
        {
        AIMoveX = 0;
        AIMoveY = 1;
        }
        while(GetSquareState(AIMoveX,AIMoveY) != EMPTY);    
    }
    // bottom row
    else if(GetSquareState(0,2) == O && GetSquareState(1,2) == O)
    {
        do
        {
            AIMoveX = 2;
            AIMoveY = 2;
        }
        while(GetSquareState(AIMoveX,AIMoveY) != EMPTY);
    }
    else if(GetSquareState(2,2) == O && GetSquareState(1,2) == O)
    {
        do
        {
        AIMoveX = 0;
        AIMoveY = 2;
        }
        while(GetSquareState(AIMoveX,AIMoveY) != EMPTY);
    }
    // vert 0
    else if(GetSquareState(0,0) == O && GetSquareState(0,1) == O)
    {
        do
        {
        AIMoveX = 0;
        AIMoveY = 2;
        }
        while(GetSquareState(AIMoveX,AIMoveY) != EMPTY);
    }
    else if(GetSquareState(0,2) == O && GetSquareState(0,1) == O)
    {
        do
        {
            AIMoveX = 0;
            AIMoveY = 0;
        }
        while(GetSquareState(AIMoveX,AIMoveY) != EMPTY);
    }
    // vert 1
    else if(GetSquareState(1,0) == O && GetSquareState(1,1) == O)
    {
        do
        {
            AIMoveX = 1;
            AIMoveY = 2;
        }
            while(GetSquareState(AIMoveX,AIMoveY) != EMPTY);
    }
    else if(GetSquareState(1,2) == O && GetSquareState(1,1) == O)
    {
        do
        {
            AIMoveX = 1;
            AIMoveY = 0;
        }
        while(GetSquareState(AIMoveX,AIMoveY) != EMPTY);
    }
    //vert 2
    else if(GetSquareState(2,2) == O && GetSquareState(2,1) == O)
    {
        do
        {
            AIMoveX  = 2;
            AIMoveY = 0;
        }
        while(GetSquareState(AIMoveX,AIMoveY) != EMPTY);
    }
    else if(GetSquareState(2,0) == O && GetSquareState(2,1) == O)
    {
        do
        {
            AIMoveX = 2;
            AIMoveY = 2;
        }
        while(GetSquareState(AIMoveX,AIMoveY) != EMPTY);
    }
    // diagonal 1
    else if(GetSquareState(0,0) == O && GetSquareState(1,1) == O)
    {
        do
        {
            AIMoveX = 2;
            AIMoveY = 2;
        }
        while(GetSquareState(AIMoveX,AIMoveY) != EMPTY);
    }
    else if(GetSquareState(2,2) == O && GetSquareState(1,1) == O)
    {
        do
        {
            AIMoveX = 0;
            AIMoveY = 0;
        }
        while(GetSquareState(AIMoveX,AIMoveY) != EMPTY);
    }
    //diagonal 2
    else if(GetSquareState(0,2) == O && GetSquareState(1,1) == O)
    {
        do
        {
            AIMoveX = 0;
            AIMoveY = 2;
        }
        while(GetSquareState(AIMoveX,AIMoveY) != EMPTY);
    }
    else if(GetSquareState(0,2) == O && GetSquareState(1,1) == O)
    {
        do
        {
            AIMoveX = 2;
            AIMoveY = 0;
        }
        while(GetSquareState(AIMoveX,AIMoveY) != EMPTY);
    }
    // mid 0
    else if(GetSquareState(0,0) == O && GetSquareState(2,0) == O)
    {
        do
        {
            AIMoveX = 1;
            AIMoveY = 0;
        }
        while(GetSquareState(AIMoveX,AIMoveY) != EMPTY);
    }
    //mid 1
    else if(GetSquareState(1,0) == O && GetSquareState(2,1) == O)
    {
        do
        {
            AIMoveX = 1;
            AIMoveY = 1;
        }
        while(GetSquareState(AIMoveX,AIMoveY) != EMPTY);
    }
    // mid 2
    else if(GetSquareState(0,2) == O && GetSquareState(2,2) == O)
    {
        do
        {
            AIMoveX = 1;
            AIMoveY = 2;
        }
        while(GetSquareState(AIMoveX,AIMoveY) != EMPTY);
    }
    //diag 1
    else if(GetSquareState(0,0) == O && GetSquareState(2,2) == O)
    {
        do
        {
            AIMoveX = 1;
            AIMoveY = 1;
        }
        while(GetSquareState(AIMoveX,AIMoveY) != EMPTY);
    }
    //diag 2
    else if(GetSquareState(2,0) == O && GetSquareState(0,2) == O)
    {
        do 
        {
            AIMoveX = 1;
            AIMoveY = 1;
        }
        while(GetSquareState(AIMoveX,AIMoveY) != EMPTY);
    }
    else 
    {
    do 
    {
        AIMoveX = rand() % 3;
        AIMoveY = rand() % 3;
    }while(GetSquareState(AIMoveX,AIMoveY) != EMPTY);
    }
    }
void Game::DoAITurnRand()
{
    AIGetNextMoveRand();
    SetSquareState(AIMoveX,AIMoveY,activePlayer);
    EndTurn();
}

do while循环是垃圾。想想看,如果你的规则做出了一个错误的选择(游戏邦注:比如试图在一个填满的方块上玩游戏),那么再次做出同样的错误选择并没有什么帮助。事实上,这就是为什么你会"冻结"。您需要重新组织代码的逻辑。我建议,如果你的AI选择了一个非法的方块,那么你应该回到你的随机选择代码,那么至少你会得到一个合法的移动。

像这样

// no move selected yet
AIMoveX = -1;
AIMoveY = -1;
// AI rules
if(GetSquareState(0,0) == O && GetSquareState(1,0) == O)
{
    AIMoveX = 2;
    AIMoveY = 0; 
}
else if(GetSquareState(2,0) == O && GetSquareState(1,0) == O)
{
    AIMoveX = 0;
    AIMoveY = 0;
}
// lots more rules
...
// check for fallback to random move
if ((AIMoveX == -1 && AIMoveY == -1)             // if no rules applied
    || GetSquareState(AIMoveX,AIMoveY) != EMPTY) // or if the square is not empty
{
    // pick a random square
    do 
    {
        AIMoveX = rand() % 3;
        AIMoveY = rand() % 3;
    }
    while(GetSquareState(AIMoveX,AIMoveY) != EMPTY);
}

我最初将AIMoveX和AIMoveY设置为-1,以表明尚未选择任何规则。如果在检查完所有规则后它们仍然是-1,那么我就知道没有规则被选中,我必须随机选择。如果一个规则被选中了,但它选中了一个非空的方块,那么我也会随机选择。我在代码末尾测试了这两种情况。

你必须仔细考虑你写的代码到底是做什么的。在一个地方放一个do while循环,因为它在另一个地方有效,这是不对的。