我正在尝试使用alpha-beta pruning
方法为井字游戏开发一个AI。我需要尽可能快地检查获胜情况,因为AI将遍历许多不同的可能游戏状态。目前我已经想到了两种方法,但都不是很高效。
- 创建一个大型元组,用于评分所有可能的四连胜条件,并遍历该元组。
- 使用for循环,检查水平、垂直、左对角和右对角。这种方法似乎比
#1
慢得多。
有人会推荐如何做吗?
回答:
从你的问题来看,你的方法如何实现有点不清楚。但从alpha-beta剪枝来看,似乎你想查看许多不同的游戏状态,并在递归中为每个状态确定一个“分数”。
一个非常重要的观察是,一旦发现四连胜,递归就会结束。这意味着在递归步骤开始时,游戏棋盘上没有任何四连胜的情况。
利用这一点,我们可以直观地看出,在该递归步骤中放置的新棋子必须是任何在递归步骤中创建的四连胜的一部分。这大大减少了从总共69个(21个垂直,24个水平,12+12个对角线)四连胜位置到最多13个(3个垂直,4个水平,3+3个对角线)的解决方案搜索空间。
这应该是你第二种方法的基础。对于一个简单的实现,它将需要最多52次(13*4)检查,或者对于更快的算法,需要25次(6+7+6+6)检查。
我认为,对于这种获胜检查,很难超过25次布尔检查,但我猜你的#1方法通过一些额外的内存使用来减少每个递归步骤的计算量。最简单的方法是存储8个整数(对于这个应用,单字节就足够了),它们代表在8个方向上可以找到的最长的同色棋子链。
利用这一点,获胜检查可以减少到8次布尔检查和4次加法。简单地获取新放置棋子两侧的链长度,检查它们是否与棋子同色,如果是,则将它们的长度相加并加1(对于新放置的棋子)。
从这个计算来看,似乎你的#1方法可能是最有效的。然而,它维护数据结构的开销更大,并且使用更多的内存,除非你可以通过引用传递,否则应该避免使用。另外(假设布尔检查和加法的速度相似)即使忽略开销,更难的方法也只赢得了2倍的优势。
我做了一些简化,有些解释可能不是很清楚,如果你有任何进一步的问题,请问我。