【问题标题】:Issues with AI for a tic tac toe game in C++C++ 井字游戏的 AI 问题
【发布时间】:2013-04-07 04:24:45
【问题描述】:

所以我的井字游戏 AI 存在一些问题。人工智能是纯粹的防御性的,所以它总是会阻止你。它通常最初适用于我的第一种情况,因此例如,如果我先播放左上角然后播放中上角,它将始终位于右上角。其他情况,比如我玩两条对角线,可能会冻结游戏,或者让我再转一圈。这些问题只有在我实现了我有缺陷的智能 AI 之后才出现。最初,该程序有一个“愚蠢的 AI”,可以选择随机点,如您将在代码底部看到的那样。此外,我认为问题在于某些阻塞条件可能会相互冲突并导致问题。我怎样才能解决这个问题?相关代码如下: 坐标基于井字游戏网格,左上角为 (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();
}

【问题讨论】:

  • 你为什么使用while循环?它不应该只需要每转移动一次吗?
  • 一个最小的完整示例是不是太多了?
  • 最初的 AI 代码,随机空间分配,来自我用来编写这个程序的教程。之后我只是对阻塞代码进行了建模。我所知道的是,如果没有那个 while 循环,AI 可以在填充空间中播放,或者程序冻结。 @Beta,一个完整的例子是什么?
  • 拿出一张纸,画一个井字棋盘,然后检查每个测试块。其中有些有意义,有些则没有。例如,当 (1,0) 是 O,并且 (1,1) 是 O,AI 应该选择 (1,2) 来阻止,但它没有。相反,它会尝试选择 (1,0),这已经是一个 O。或者我错过了一些关于你的变量表示什么以及你的函数做什么?
  • 不,你做对了。我只是不小心把坐标弄错了。我会修复它们,看看会发生什么。

标签: c++ artificial-intelligence


【解决方案1】:

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 循环是不对的。

【讨论】:

  • 非常感谢。我为推断 do while 循环感到尴尬,但现在已经吸取了教训。
猜你喜欢
  • 1970-01-01
  • 2015-03-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-16
  • 1970-01-01
相关资源
最近更新 更多