Tic Tac Toe AI Bugs

时间:2013-09-13 02:24:06

标签: algorithm artificial-intelligence tic-tac-toe

我正在尝试为Tic Tac Toe实施一个AI,它足够智能,永不丢失。我尝试了两种不同的算法,但AI仍然会出错。

我从这个minimax alpha-beta pruning algorithm开始。这是一个现场演示:http://iioengine.com/ttt/minimax.htm

它运行没有错误,但是如果你先左下角,那么底行的另外两个方块中的任何一个 - AI都没有看到它。我确信这不是minimax算法中的缺陷 - 任何人都可以在我的源代码中看到错误吗?您可以检查演示页面以查看所有内容,但这里是主要的ai功能:

function bestMove(board,depth,low,high,opponent){
      var best=new Move(null,-iio.maxInt);
      var p;
      for (var c=0;c<grid.C;c++)
        for(var r=0;r<grid.R;r++){
          if (board[c][r]=='_'){
            var nuBoard=board.clone();
            nuBoard[c][r]=getTypeChar(opponent);
            if(checkWin(nuBoard,getTypeChar(opponent)))
              p=new Move([c,r],-evaluateBoard(board,getTypeChar(opponent))*10000);
            else if (checkScratch(nuBoard))
              p=new Move([c,r],0);
            else if (depth==0)
              p=new Move([c,r],-evaluateBoard(board,getTypeChar(opponent)));
            else {
              p=bestMove(nuBoard,depth-1,-high,-low,!opponent);
            }
            if (p.score>best.score){
              best=p;
              if (best.score > low)
                low=best.score;
              if (best.score >= high) return best;
            }
          }
        }
      return best;
    }

如果你对negamax更熟悉,我也试过了。我从this page直接解除了逻辑。这是一个现场演示:http://iioengine.com/ttt/negamax.htm

一旦你达到胜利状态就会冻结,但你已经可以看到AI非常愚蠢。代码集成有问题吗?

如果您发现我的代码中有一个漏洞阻止这些algrothims正常运行,请告诉我。日Thnx。

使用代码更新:

function checkWin(board,type){
      for (var i=0;i<3;i++)
        if (evaluateRow(board,[i,0,i,1,i,2],type) >= WIN_SCORE
          ||evaluateRow(board,[0,i,1,i,2,i],type) >= WIN_SCORE)
          return true;
      if(evaluateRow(board,[0,0,1,1,2,2],type) >= WIN_SCORE
       ||evaluateRow(board,[2,0,1,1,0,2],type) >= WIN_SCORE)
        return true;
      return false;
    }

function evaluateBoard(board,type){
      var moveTotal=0;
      for (var i=0;i<3;i++){
        moveTotal+=evaluateRow(board,[i,0,i,1,i,2],type);
        moveTotal+=evaluateRow(board,[0,i,1,i,2,i],type);
      }
      moveTotal+=evaluateRow(board,[0,0,1,1,2,2],type);
      moveTotal+=evaluateRow(board,[2,0,1,1,0,2],type);
      return moveTotal;
    }

2 个答案:

答案 0 :(得分:2)

问题在于您的evaluateBoard()功能。 evaluation function是minimax / negamax算法的核心。如果您的AI表现不佳,问题通常在于每次移动时对电路板的评估。

对于棋盘的评估,你需要考虑三件事:获胜动作,阻挡动作以及导致分叉的动作。

获胜移动

静态评估函数需要知道移动是否会导致当前玩家获胜或失败。如果移动导致当前玩家丢失,则需要返回非常低的负数(低于任何常规移动)。如果移动导致当前玩家获胜,则需要返回非常高的正数(大于任何常规移动)。

重要的是要记住,这个评估必须是relative to the player whose turn the AI is making.如果AI目前正在预测人类玩家将要移动的位置,那么评估必须从人类玩家的角度来看待棋盘。当AI转向时,评估必须从计算机播放器的角度来看待电路板。

阻止移动

当您运行评估功能时,AI实际上并不认为阻止人类玩家是有益的。您的评估函数看起来只计算可用移动的数量并返回结果。相反,你需要为有助于AI获胜的动作返回更高的正数。

要考虑阻止,您需要弄清楚玩家是否在开放的行,列或对角线中有2个令牌,然后将阻挡方块的得分高于任何其他方块。因此,如果轮到计算机移动,并且人类玩家在开放行中有2个令牌,则该行中的第3个方格需要具有高正数(但不能高于获胜方块)。这将导致计算机优先于任何其他方格。

通过仅考虑获胜动作和阻止动作,你将拥有一台相当不错的计算机。

分叉移动

分叉移动会导致计算机出现问题。主要的问题是计算机“太聪明”,因为它本身就是好的。因为它假设人类玩家每次都会做出最好的动作,所以它会发现所有可能造成的动作最终会以失败告终的情况,因此它只会在棋盘上选择第一步。别无其他。

如果我们通过你的例子,我们可以看到这种情况发生:人类玩家左下角,计算机占据中间位置。

   | O |
---+---+---
   |   |
---+---+---
 X |   |   

当人类玩家移动到右下角时,计算机会看到如果它试图阻止该移动,那么人类玩家将采取的最佳动作是采取中间方格,从而产生一个分叉和一个胜利对于人类(虽然即使人类犯错误也不会发生这种情况,但计算机并不知道这一点。)

   | O |
---+---+---
   | X |
---+---+---
 X | O | X  

因为无论计算机是阻止还是不阻止人类获胜,计算机都将失败,阻止人类实际上会冒出最低分(因为它会导致计算机丢失)。这意味着计算机将获得最佳分数 - 中间正方形。

你必须弄清楚处理这种情况的最佳方法是什么,因为每个人都会以不同的方式玩它。这只是需要注意的事情。

答案 1 :(得分:1)

使用Tic-Tac-Toe的纯Minimax实现,A.I。永远不要输。在最坏的情况下,它应该进入平局。

纯粹的Minimax,我指的是一个探索每一个可能的移动(实际上从一个移动到另一个移动)的实现,并为所述移动和转换创建一个树(从树顶部的空板开始,在所有可能的第一步中分支,然后是所有可能的第二步,等等。)

(还有启发式Minimax,你不会从一开始就渲染树节点中的所有位置,但只能达到一定的深度。)

树应该只有叶子的位置才能结束游戏(X胜利,胜利或抽奖)。这种用于分类Tic-Tac-Toe(3x3板)的树包含5477个节点(不包括顶部的全空板)。

一旦创建了这样的树,就可以通过简单地评估游戏结束方式直接对叶子进行评分:包含板状态的叶节点的最高分,其中A.I.获胜,0分为平局,以及人类玩家赢得的董事会状态节点的最低分数。

(在启发式Minimax中,你必须创建一个“guesstimation”函数,它会评估部分树的叶子并相应地分配min / 0 / max分数 - 在这个实现中,AI可能会丢失最后,这个机会与你的“猜测器”功能在评估部分游戏状态时的效果成反比。)

接下来,树的所有中间非叶节点都根据其子节点进行评分。显然,你最初只做最低限度的非叶子节点有得分的孩子(叶子节点)从中得出自己的分数。

(在Tic-Tac-Toe的背景下,制作Minimax的启发式实现毫无意义,因为渲染具有5477 + 1个节点的树相当便宜,然后对它们进行全部评分。这种实现很有用对于有很多分支的游戏(对于给定的游戏状态有很多可能的动作),从而制作一个慢速/记忆猪的完整树 - 例如象棋))

最后,您将拥有一个包含所有可能的Tic-Tac-Toe游戏的数据结构,并准确了解为响应人类玩家所做的任何动作而执行的最佳动作。因此,由于Tic-Tac-Toe规则如何运作,Minimax A.I.只会赢(如果人类玩家至少犯了一个关键错误)或抽奖(如果人类玩家总是做出最好的移动)。无论谁做出第一步,这都是正确的。

我自己实现了这个,它按预期工作。

以下是一些更精细的观点(我有点挣扎):

  • 确保用于评估电路板的功能运行良好,即在X和O的获胜/绘制情况下正确发现。此功能几乎用于Minimax树的每个节点当你构建它时,让它出错会导致看似有效但实际上有缺陷的代码。广泛测试这部分

  • 确保正确导航树,特别是当您对中间节点进行评分时(以及当您搜索下一个要制作的节目时)。一个简单的解决方案是在树的旁边制作包含每个树深度级别的每个中间节点(非叶节点)的哈希表。这样,当您进行自下而上的评分时,您将确保在正确的时间获得所有节点。