筹划阶段
前一段时间,我制作了一款五子棋AI的程序 。那款AI是通过大量的判断和一个很简单的打分程序来作出判断的。但是,这种非常简陋的算法有很多的不合理之处:
比如说,对于我们的打分算法,下图就是一个可能会导致它做出错误判断的例子:
假设上图中是棋盘的一部分,三个圆圈表示三个白色棋子,那么对于这种情况,我们的打分算法将分别给这三颗棋子的周围八个格子各加上一分。这样一来,图中打叉的那个格子将被加上三分。也就是说,对于这个打分程序来说,打叉的那个格子的权值和活三两旁的格子的权值是一样的。这就会导致我们的算法在活三和图中情况同时出现时,做出错误的判断。这个时候,引入一个新的算法就会变得非常重要。
神经网络
神经网络是机器学习的一种,我是通过B站上的一个视频学习到这个算法的。
按照我的理解,神经网络就是利用事先记录好的数据进行统计和分析来得出下一步的判断。
将它带入到我们的作品里,实现方法大致就是这样的:
对于每一次用打分算法或者神经网络做出的决定,我们都将做出决定之前棋盘的样子(即列表chess)、做出的决定(包含两个变量,表示AI决定落白子的位置的横纵坐标)以及最后的结果(输或赢,用-1或1表示)存储下来。
对于每一次即将进行的神经网络决定,我们遍历一遍之前做过的所有决定,挑出其中棋盘样子和当前棋盘样子相同的记录,并统计这些记录中的胜负情况(就是看白子落在哪赢得次数多、输得次数少)进行落子
当程序结束的时候,将所有的记录存在一个文件里,以便下一次程序开始的时候恢复上一次的记录。
但是单纯这样做会面临很多问题,因此我们需要在细节上对它进行优化
优化
1简化学习过程
首先,我们希望我们做出来的神经网络一开始就具有一定的水平,而不是像一个小白一样随便下,就像下面那样:
上面那种情况出现的原因是因为一开始程序没有相关经验,因此在选择最佳格子的时候就选中了最右上角的格子(也就是第一个格子)
因此我选择将打分算法和神经网络相结合。打分算法的本质就是通过计算给还没有落子的格子赋值,最后挑选值最大的那个格子落子。同理,神经网络算法也可以被更改成将之前的记录中的每一次抉择所对应的输赢(赢为1,输为-1)加到对应的格子上的值中。这样我们就做到了将打分算法和神经网络有机结合,使这两个算法共同做出决定。
但是这种方法还存在两个问题
1.1负权值问题
读过我之前的讲解的人都知道,在chess列表中,我们用-1表示黑子,用-2表示白子,0表示空。在以前的打分过程中,我们的打分算法只会给值为零的格子加上数值,因此不存在将值为零的格子加成负数的情况。
但是神经网络就有不同。它存在给格子加上负权值的可能性,也就会有可能将原本大于等于零的值变得小于零。这样就会出现下着下着黑方或者白方突然多出来一个子的情况,非常破坏气氛。
因此我们在这里选择做一个判断,如果说在某一次打分的过程中格子的值变负了,就撤销这次打分动作,并给棋盘上其余的空格子的权值加上这次打分的相反数。这样就解决了格子权值可能变负的问题
2.2 旧病复发(bushi
其实神经网络和打分程序相结合的方法并不能完全解决掉程序随便下的问题,因为神经网络的经验有可能正好抵消掉打分程序所打的分,从而又回到上面视频中的那个样子。
因此这里我们选择对程序每一次所能落子的位置做一个限制,从而避免程序下出像视频中那样无厘头的子。
但是这个限制的严苛程度是需要控制的。神经网络的本质是通过尝试总结经验从而找到最好的方法,因此这个限制不能过于死板,否则会阻碍神经网络继续寻找更好的方法;也不能太宽松,否则会出现视频中的那种情况。
因此我选择将神经网络所能落子的位置限制在别的子的周围,即神经网络所落子的位置周围3*3的范围内必须有至少一个子。这样既保证了神经网络有足够的发展空间,也限制了它的瞎下行为
我已经将源代码和exe文件上传到了百度网盘上,
提取码:7v1u
更多系列文章,请关注微信公众号Jerrywriting或者B站up主Jerrycjk