【问题标题】:Tic-Tac-Toe AI: How to Make the Tree?井字游戏 AI:如何制作树?
【发布时间】:2010-04-30 12:04:15
【问题描述】:

在制作井字游戏机器人时,我在试图理解“树”时遇到了很大的困难。我理解这个概念,但我不知道如何实现它们。

有人可以向我展示一个如何为这种情况生成树的示例吗?还是生成树的好教程?我想困难的部分是生成部分树。我知道如何实现生成一整棵树,但不知道它的一部分。

【问题讨论】:

  • 什么样的树? Minimax 树?
  • 存储下一个可能移动的状态的任何树。 minimax树会起作用,我只是想看看“树”是如何填充/导航/等的。我没有任何处理树木的经验

标签: c++ tree artificial-intelligence tic-tac-toe


【解决方案1】:

想象一下,在井字游戏中的任何一点,每一个可能的动作都是一个分支。板的当前状态是根。一个动作是一个分支。现在假设(一次一个),每个分支都成为当前状态。每个可能的移动都成为一个新的分支。树的叶子是当最后一步完成并且棋盘已满时。

你需要一棵树的原因是,一旦它建成,你需要找出哪个分支有最多的叶子,这是“获胜”的场景。您构建所有可能结果的分支,将获胜的总数相加,然后采取最终有机会获得最多胜利的行动。

让树变成这样:

class Node {
public:
   std::list< Node > m_branches;
   BoardState m_board;
   int m_winCount;
}

std::list< Node > tree;

现在,您遍历树中的分支列表,并为每个分支遍历其分支。这可以通过递归函数来完成:

int recursiveTreeWalk( std::list< Node >& partialTree)
{

   for each branch in tree
       if node has no branches
           calculate win 1/0;
       else
           recursiveTreeWalk( branch );

   partialTree.m_winCount = sum of branch wins;
}

// initial call
recursiveTreeWalk( tree )

非常伪代码。

【讨论】:

  • ...话虽如此,目前还不是真正的人工智能,而是严格确定所有可能的结果,并承担完全适当的风险。
  • 对,感谢解释的帮助,但我遇到的主要问题是实现这一点。我完全理解这个概念,但是生成树并导航它让我很难过。我正在寻找一些可以帮助我的源代码,甚至是教程。在我理解代码中的一个概念之前,我的大脑需要先看一个例子。
  • 为了让它更像人工智能,你可以使用最大深度来限制向前看。或者一个计时器来限制将花费在前瞻上的时间量 - 尽管在 TTT 上,完整树的计算将在纳秒内完成。
【解决方案2】:

我认为您不需要在内存中保留一棵树。您只需要实现一个递归函数,其工作原理如下:

Move getBestMove(Board state, boolean myTurn)

然后您只需递归,直到您达到获胜、失败或平局状态。

如果您将调用堆栈画在纸上,随着时间的推移,它会看起来像一棵树。您应该返回导致对手(肯定/最有可能)失败的节点的移动(即使他也使用 getBestMove 玩)

但是,对于像井字游戏一样小的状态空间,您可以简单地使用最佳动作进行完整的查找表! :-)

【讨论】:

  • 我想这是我不明白的。我认为在内存中创建了一个实际的树结构。这就是我现在实现机器人的方式,使用没有树的递归函数。
【解决方案3】:

您可能会觉得这篇 codeproject 文章很有趣:

Solve Tic Tac Toe with the MiniMax algorithm

它是在 C# 中的,但在 C++ 中改编它不会有任何问题。

当我尝试用 C++ 实现我的第一个井字游戏时,这篇文章对我来说也是一本不错的读物:

Minimax Explained

【讨论】:

    【解决方案4】:

    如果你想在内存中生成树(这不是必需的),也许可以使用如下算法(伪代码):

    GenTree(State s):
      T <- empty tree  // T is a tree of States
      SetRoot(T, s)
    
      ForEach (s' in Successors(s)):
        AddChild(T, GenTree(s'))
    
      return T
    
    // Call it
    GenTree(currentMove)
    

    在哪里

    Successors(s)  // returns a list of successor states of s
    AddChild(p, n)  // adds n to the list of p's children
    

    【讨论】:

      【解决方案5】:

      实现井字游戏可能是 AI 方面最简单的问题 和搜索空间。

      关键是用MinimaxIterative deepening Depth-first searchAlpha-beta pruning算法解决问题。

      这是我用 Python 编写的游戏 implementation,它只有大约 200 行代码,并且能够以 Human vs. HumanHuman vs. ComputerComputer vs. Computer 玩游戏。它还保留有关深度和达到/修剪的节点数量的统计信息,以达到最佳移动。

      我强烈推荐edX.org人工智能course,它提供了当前人工智能主题和解决方案的基础知识。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-03-11
        • 1970-01-01
        • 2023-03-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多