问题
我在做跳棋游戏时利用树来存储每一个棋子的合法路径,构造落点树时,要求遍历路径上每一个可能的落点。于是出现了一个尴尬的状况——三个落点围成了圈,如下图。
黑色实心点为棋子位置,三个虚线表示位置为形成循环的空位。其他棋子构造合法落点树时,一旦遍历到三个位置中的一个,就会陷入循环。因为棋子在三个中的任一个位置时,其余两个点都是合法落点,可以无限跳转下去,这条路径会有无限长。
出现这种情况可能是由于我写的人工智能算法不够机智,后续调试过程中发现了另外一些类似棋局状况,即三个空位形成循环。
解决办法
-
遍历已经形成的落点树,重复点舍去,重复次数过多时停止遍历(未实现)
遍历已经形成的落点树显然是一种明显思路,但是对于我的程序来说实现较为复杂。
我写的构造落点树程序在可以隔一子跳跃时发生递归,递归后只保存了部分上一层数据,也就是本次跳跃的起点或者说来路,最多只能追溯两层数据。然而形成循环基本是两次遍历以后的结果,即涉及到三层数据,以我现有的程序不满足直接判断重复落点的条件。且我也不能排除以后出现四子循环出现的可能性。于是考虑将落点树改为类中的一个私有变量,其在方法中的作用范围类似于全局变量(为方便表述下文称其类别为全局变量)。
但是尝试后发现,在递归中几乎无法使用这种有层次的全局变量(有层次的变量即多维变量)。上网搜索后发现一般递归中使用全局变量都没有层次,例如利用递归求累加和等。
后又尝试将函数中的变量作为缓存,一部分遍历完成后将结果直接替换到落点树中。没写成。总是会有重复替换,合适的替换位置不存在。所以从全局变量的角度来说,遍历形成的深度是没有意义的。一维变量更适合作为全局变量使用。
-
记录跳转次数,跳转过多时怀疑出现循环(已实现)
没办法阻止循环出现,就在循环出现后处理。我写的人工智能太废柴,所以一般跳转次数不会太多,但是就算跳转很多次,有棋盘高度的限制,跳转次数一般也不会超过20。
跳转次数基本等同于递归次数,所以递归次数有一个上限,我将其设置为10,正常来讲我的递归次数不会超过10,一旦超过就意味着有异常,我就有理由怀疑出现了循环。确定循环出现方法:
我把棋子路径的六个方向分别标记为1-6,每一次跳转时记录跳转方向,列表存储,称其为方向列表。如果出现循环,则方向列表中的数据一定有循环。
在出现循环的基础上,方向列表中的最后一个数据一定属于循环数据中的一个。检测其出现次数,就算路径方向集中,同一方向也不应该出现太多次。所以同一数据出现若超过3次,则判定为出现循环。处理循环的方法:
返回空列表。(待改进,貌似有些过于简单粗暴。(但有效))#怀疑出现循环 if firstMove>10: #最后一个元素一定在循环中,所以确认其数量,过大时确认为循环出现 if wayOfPlace.count(wayOfPlace[len(wayOfPlace)-1])>3: #处理循环 return []