我在制作井字棋机器人时,在理解“树”这个概念上遇到了巨大的障碍。我理解这个概念,但我无法弄清楚如何实现它。
有人能展示一下如何为这种情况生成一棵树的例子吗?或者有一个关于生成树的好教程吗?我猜难点在于生成部分树。我知道如何实现生成整个树,但不知道如何生成其部分。
我在制作井字棋机器人时,在理解“树”这个概念上遇到了巨大的障碍。我理解这个概念,但我无法弄清楚如何实现它。
有人能展示一下如何为这种情况生成一棵树的例子吗?或者有一个关于生成树的好教程吗?我猜难点在于生成部分树。我知道如何实现生成整个树,但不知道如何生成其部分。
假设在井字棋棋盘上的任意一点,每个可能的走法都是一个分支。当前棋盘状态是根。每一步走法都是一个分支。现在假设(逐个假设),每个分支都成为当前状态。每个可能的走法都成为一个新的分支。树的叶子节点是最后一步走完并且棋盘已满的时候。
需要有这样一棵树的原因是,建立完毕之后,您需要找出哪个分支拥有最多的“胜利”场景。您可以构建所有可能结果的分支,计算总胜利数,然后选择可能获得最多胜利的那一个走法。
将树形结构制作成如下图:
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 )
非常伪代码。
我认为你不需要将一棵树存在内存中。你只需要实现一个递归函数,类似于下面的例子:
Move getBestMove(Board state, boolean myTurn)
您可能会发现这篇CodeProject文章很有趣:
它是用C#编写的,但将其改为C++也不会有任何问题。
当我尝试在C++中实现我的第一个井字棋游戏时,这篇文章对我也很有帮助:
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
实现井字棋游戏可能是在AI和搜索空间方面解决的最简单问题。
关键是要使用Minimax, 迭代加深深度优先搜索和Alpha-beta剪枝算法来解决问题。
这是我用Python实现的游戏代码,仅有约200行代码,并且具备人对人
、人对电脑
和电脑对电脑
的游戏能力。它还保留了有关深度和到达/剪枝节点数量的统计数据,以指导最佳移动。
我强烈推荐 edX.org
人工智能课程, 它可以为您提供关于当前AI主题和解决方案的基本知识。