当速度是主要关注点时,代表跳棋板的最佳数据结构是什么?

时间:2010-10-15 22:27:51

标签: algorithm artificial-intelligence

我目前正在实施与跳棋非常相似的东西。所以,我有这个桌面游戏,有白色和黑色的片断。如果没有白色或黑色的碎片,你就不会有碎片。

我目前正在使用GetValidMoves()方法,它将返回当前电路板可以执行的所有当前移动。

因此,我想知道什么是代表董事会的最佳方式。天真的方法是有一个0的1和2的矩阵(没有片,白片和黑片)。

其他想法是代替电路板的矩阵表示,有2个列表(或任何其他数据结构):一个用于黑色部分,另一个用于白色。

我正在实施这个游戏来测试一些AI算法,所以我主要担心的是速度。我基本上会让2个AI玩家互相玩,每回合每个玩家应该有一个他所有有效动作的列表,然后他会选择要做的动作,这一直发生直到比赛结束(某些玩家获胜或者有一个并列)。

PS:我不是在询问人工智能算法,我只是想知道处理电路板的最佳数据结构是什么,这样可以轻松实现

  1. 查找当前玩家的所有有效动作
  2. 采取行动
  3. 确认游戏未结束(当一名玩家丢失所有棋子或一名玩家到达棋盘的另一侧时,游戏结束了。)

6 个答案:

答案 0 :(得分:12)

考虑使用位图:两个64位无符号整数,一个用于白色,一个用于黑色。然后,您可以将移动和电路板位置表示为(W x B) -> (W x B)的函数,其中 W B 分别代表可能的白色和可能的黑色位置的集合。

然后,大多数电路板位置的东西可以用整数运算来完成,这个速度大约是你能得到的。

答案 1 :(得分:6)

一种常见的方法是使用long类型的每个玩家的二进制表示 (因为棋盘上有64个方格)..正如查理已经说过..
这是一个非常好的(但是一般的)wiki article

用法很简单 - 例如,如果你想检查所有棋子是否可以向上和向右移动,将玩家的棋子重新移位7位向左移动,并检查那里是否有对手棋子,然后将它们移动7再次留下位,并检查这些方块是否清晰...
我曾经在Reversi比赛中使用过一次,可以说实施起来并不太难 HTH。

答案 2 :(得分:1)

我也会使用位图。检查1,2和3的函数写入有点不直观,但应该非常快。

当然,您需要注意边缘情况,快速解决方案可能会对索引进行一些整数和模运算。

答案 3 :(得分:1)

首先,值得注意的是,在棋盘中,棋盘上的一半方块永远不会被使用,所以你真的只需要一个32个项目的阵列,而不是64个。考虑到国王,你可以从0到4而不是0到2(虽然当我这样做时,我发现使用-3到+3更容易,所以红色和黑色的值具有相同的幅度和相反的符号)。

答案 4 :(得分:0)

就列表而言,我强烈建议不要在这种情况下使用使用链表的结构。您可能已经知道要调查的位置(x-y坐标),因此链接列表需要O(n)时间来简单地获取棋盘空间的值。正如其他答案所提到的,位图或长方法是理想的。

就如何组织数据而言,我认为黑色和白色都存储在同一结构中的实现将是理想的。你会有一些开销,因为在二进制文件中存储23需要相同数量的内存,但如果你正在编写检查器,你可能还需要存储“kinged”数据。能够通过执行单个查找来检查空间是否打开应该会提供显着的性能优势。

希望这有帮助。

答案 5 :(得分:0)

这取决于您的AI算法将要做什么。大多数AI算法都会对可能的移动进行某种搜索,至少要提前几步。在这种情况下,您将制作大量的电路板表示副本,因为复制数据结构的时间将主导获取可能移动列表以及限制深度的时间,因此尝试保持较小是有意义的。你可以搜索。

然而,如果你不是在搜索,我会创建一个类,并存储颜色,位置,以及该作品是否为王。然后,我会有一个2维8乘8引用的数组和一个黑色链接列表和一个红色链接列表。数组的每个元素都指向红色或黑色列表中的一个部分或“空”部分(null可用于此)。移动一块时,只需更新列表中的Piece对象,并将引用从当前位置移动到新位置,将旧位置设置为空位。对于稍微增加更新的成本,您可以获得一种有效的方法来迭代任何一方的部分以及对电路板上任何特定点的状态的恒定时间查询。

你必须遍历整个列表以删除一个死片,但是这也可以通过稍微改变一块来提高效率。您可以在Piece对象中存储bool“dead”。当一块被杀死时,将dead设置为true并通过用空块替换对它的引用将其从板上移除。当您遍历任何一个片段时,只需从列表中删除任何标记为死的片段。