只是一个普遍的问题。我有一个带有alphabeta-search aigame的跳棋游戏,整体效果非常好。我想知道是否建议在板数组中存储对象引用并且有一个很好的干净代码,或者更好地使用char值数组并使用switch()语句来分支不同的部分。我想这取决于对象数组的内存(in)效率如何以及克隆它...
我将游戏位置存储在board [] []数组中,该数组引用实现片段所有特征的游戏片段对象,特别是找到可能移动的例程。
我的主要getmoves循环看起来像这样:
for(sq:Squares) {
allmoves.addAll(sq.getPossiblemoves());
}
每个方块都是类层次结构中的对象,如:
interface GamePiece {...}
class EmptySquare implements GamePiece {...}
class Pawn extends EmptySquare implements GamePiece {...}
class Queen extends EmptySquare implements GamePiece {...}
AI在alpha-beta-tree递归中寻找最佳移动,为每次递归克隆游戏板,如:
int alphabeta(Board b....) {
for(mv:b.possibleMoves) {
score = -alphabeta(b.doMove(mv),...)
}
}
其中doMove返回一个全新的Board对象,其中包含一个带有克隆游戏片段的新棋盘阵列,所以我必须做很多对象创建。它运行良好,代码非常干净。我只是不确定这在性能方面是否是一个好方法。对最佳移动的典型搜索涉及大约50000-500000个节点,这相当于游戏板的完整副本以及大约一半节点的所有引用的游戏块对象(所有叶子仅被评估并且不需要进一步克隆董事会)。它使用大约800MB的RAM。
我还可以使用一个board [] []数组来存储字符或尝试更加严格的方式来存储所有游戏片段......任何关于这会产生多大差异的经验?是否值得牺牲更好的代码与多态调用getPossibleMoves()?如果我存储char值,我将不得不根据游戏块进行分支并调用不同的子程序来获得可能的移动。我认为这对于OOP原则来说是一个糟糕的方法,但我怀疑我的方法在性能原则方面是不好的。有多糟糕,我不知道...
答案 0 :(得分:0)
我很惊讶你没有考虑使用“位板”,例如64位整数,其中N位告诉你一块是在方形N上。有了棋盘,你需要两个位板,一个用于黑色,一个红色。
可以在位操作方面完成移动生成。如果没有,你仍然可以轻松枚举板位0..63,检查件类型等;它不会改变其余代码的基本逻辑。
但现在你也可以便宜地存储巨大的换位表。这将使残局比赛变得非常好。
您可能希望从用于访问信息的抽象操作开始。为了让您的游戏发挥出色,您需要对其进行调整以允许更深入的搜索。在这种情况下,您可能会发现干净的抽象与高性能不一致。我建议你先把它弄好,然后在想要调整代码的时候用它们的实现替换抽象函数。