注:PCGO函数扔未修正添子方法。请自行修改。
一、迭代加深
1、什么是迭代加深
所谓迭代加深,就是让alpha-beta剪裁运行深度1,然后运行深度1,2,然后运行深度1,2,3。
2、为什么进行迭代加深
这样做的好处就是可以在搜索完一次之后,得到排序的依据——历史表,然后下次搜索时,历史表会给出一个大约的方向——下哪一步更好,也就是更容易产生截断了。
3、这样做增加了多少开销
实际上,单纯考虑迭代加深,它可能会多运行一点时间,但是考虑到历史表,也差不多抵消这些时间了。更何况,还有置换表(我一直不太喜欢这个名字)。
4、如何实现迭代加深
想法很简单,实际上代码也很简单,只需要实现一个循环,for i = 1 to n,i是要扫描的深度,在这个循环中调用alpha-beta剪裁即可。代码就这么几行:
整个循环中,先清空历史表(但是我感觉不应该同时置换表,当然这是后话);然后调用alpha-beta的递归函数就可以了。其他的判断都很容易理解。
二、棋盘剪裁
1、为什么剪裁棋盘
这可以大量剪裁掉不合理招法,在五子棋中,我们很容易遇见,如果下的子远每个离黑子和白子,那一定是臭棋。那么远离程度是多少呢,可能是4,因为要成5,所以最远只能离当前子4格,但是真的是这样吗?让我们大胆的猜测:其实第四格也是臭棋!为什么呢,中间有3个格的话,远离程度也太大了,需要在该方向上再连续下3子才能连起来。而我们,有多大机会能这样做呢?即使我们想,可我们成功的机会有多大呢?我想微乎其微——五子棋双方的缠绕(指互相冲堵,当然好棋是冲并且堵着……)是非常严重的,所以,我们的结论是3而不是4。
2、如何实现
我的代码中是先遍历棋盘,找到黑子或白子,然后把他们周围的非子点记录下来。当然这存在一个重复记录的问题,所以我是记录在一个bitarray里面,它的操作速度非常快,然后再次遍历它取出合理点。当然,另一种想法也许更好——遍历所有点,并记录每个三格以内有子的空点。但遗憾的是我最初意识到的是第一种做法。
这个代码在上一个示例里面已经在使用了。这里不再罗列。
三、空步剪裁
1、什么是空步剪裁
就是轮到自己不下子却不下,让对方接着下。
转载请注明出处:http://www.cnblogs.com/zcsor/
2、为什么进行空步剪裁
它基于这样一种想法:如果己方不下,那对方会下哪?这对于五子棋来讲,好处不仅仅是预测性的剪裁,更重要的是对方冲棋时,可以把冲棋点直接作为合理招法点:因为如果不去封堵,自己就要被杀死了!当然,在我的代码中,由于评价函数还不完善(这里主要指分数设置方面的不准确性),所以程序会去封堵对方的单个冲3或活2,这完全可以通过重新规划分值解决。
3、如何限制的空步剪裁
首先,什么时候进行空步剪裁。如果对方已经冲棋了(冲4,活3等)那么再让他走,无疑是不明智的。所以,只有对方不冲棋的时候,我们才进行空步剪裁。
其次,无限制的空步剪裁当然不是一个好办法。从预测的角度来看,一步貌似有点少,两步还可以,如果3步对方的冲2都成5了!所以,结论是2步。
4、如何实现
其实代码很简单,但是要建立在对alpha-beta剪裁已经充分理解的前提下。首先分析是否被冲棋,如果没有,那么空步剪裁;如果有,用冲棋点作为接下来迭代的”合理招法“。这就是思路。代码也就不复杂了,当然需要注意的是,空步剪裁对”深度“的影响:
接下来我们讨论冲棋延伸
四、冲棋延伸
1、什么是冲棋延伸
在对方冲棋时,我们无限制的进行迭代,直至分析出最终解。
2、为什么进行冲棋延伸
当对冲棋时,往往会形成比较险的连冲棋,一步失误全盘皆输,所以我们需要分析到最终局面——确切知道到底走哪步棋才是明智的。当然,这非常耗时,但同时也为置换表提供了非常多宝贵的局面。
3、如何实现冲棋延伸
基于我们的想法,我们无限延长迭代,使之达到最终解。但实际上,还是做了一些限制,我们没有真正分析全部局面的时间。具体的限制就在上面的代码中,”达到极限深度就返回局面评价“。而真正的冲棋延伸,实现起来很简单:当被冲棋时,我们的迭代过程传入的参数不是n-1,而是n,这样深度不会减少到0,也就会继续分析下去:
那么,这集就结束了。
本集代码:
下一集预告:
静态搜索。而静态搜索之后,将会是置换表。置换表的发布可能要久一些。因为这几天时间比较少,要实施好爸爸计划,还有一些其他的事情需要处理。
全部文章和源码整理完成,以后更新也会在下面地址: