【再谈】五子棋AI循序渐进【2】五子棋的局面评价
我们都知道α—β剪裁的准确程度、局评价函数的快慢、招法排序的好坏这些因素是我们的引擎棋力高低的决定性因素。剪裁的准确度与局面信息息息相关但这不在我们这次讨论的范围之内。这次我们要讨论的是一种提高局面评价速度和招法排序程度的五子棋棋型表示方法:
一、局面评价函数
最基本形式就是子力得分的差值,当然还有很多因素影响着评价结果。我们这里采用的是棋型得分差值(因为代码我还没有完全完成,所以没有测试先行权问题,这也是我的程序一直没有使用的一个因子,现在的想法是这个因子应该在子数一样时为0,而多子一方应该做适当的减法),也就是我们计算黑棋成5、冲四、活四、冲3……全部棋型的个数并根据我们设定的每种棋型的分值得到一个和,白棋也是如此:
VLB=LB5*K5+LB41*K41+LB42*K42+LB31*K31……
VLW也进行类似计算
若走棋方为白棋,则局面评价返回VLW-VLB,若为黑棋则VLB-VLW。这是我们所熟悉的算法,这里最耗时的是LB5,WB5,LB41,WB41,LB42,WB42……的获取,也就是黑棋、白棋双方各种棋型的个数。前面我采用的是模板匹配的方式,那非常慢。这次我们讨论的新方法将避免识别。
二、招法排序
在很多程序中,采用历史表技术来得知走一步棋可能好或坏,这种技术在历史表排序算法足够好的情况下,使用α—β剪裁算法将产生非常多的截断,从而产生令人振奋的效果。前面我们的程序也使用了这种方法。但是,我们仔细研究就会发现,五子棋走棋的位置选择,往往可以从当前局面出发(我是指不尝试下子而是直接观察——从冲点看,我们以前的程序也是这样做的),直接得到更好的排序方法,至少,我们知道,当走几步之后,再去下一步只能得到一个冲2的棋不会好到哪去。所以,我们的新方法除了快速得到棋型也必须能够快速的得出棋型上的冲棋点。
三、新的局面表示方法
基于前面的原因,还有说得麻一点就是对五子棋内在机理的初步的深入研究基础上,我们可以发现:五子棋最终的目的就是成5,哇咔咔……成5的过程呢?就是不断的不断的增加连接的个数,哇咔咔咔……别拍砖,其实道理都知道……于是我们可以发现,在五个位置上,每个位置只能是0,1,2这几种种情况,也就是说,如果我们以5个位置为基本单元来考察五子棋,那么五子棋的棋型演变只有3*3*3*3*3种情况。我们枚举这些情况成为一个表,这个表的元素用以下结构来表示:
sooxx mod
public vl as integer
public smods(14) as mod
end sooxx
就可以了。vl是当前的棋型的得分,只有各位均为0或2,或者均为1或2(我们用0表示白棋,1表示黑棋,2表示空,原因可以参考前面的代码中数组的组织和走棋者表示)时才有分,其他都是0分。smods就是这个意思:
smods(0) 为第一位为变为0时的结构的引用,smods(1)为第一位变为1时的结构引用,smods(2)为第一位变为2时的结构引用,
smods(3) 为第二位为变为0时的结构的引用,smods(4)为第二位变为1时的结构引用,smods(5)为第二位变为2时的结构引用,
以此类推。这样导致我们更新棋型时,只需要更新棋型的引用就可以了。算法就像这样:
mm=mm.smods(point*3+player)
就可以得到新的棋型了,当然,在一个位置上下子时,最多时要更新20个这样的棋型。也就是说,我们需要在15长的一维数组中进行寻址20次。这也许可以忍受吧。至少省略掉了模板匹配,而且可以更详细的设置每种棋型的分值。
当然,我们还需要解决这样一个问题:从这个5长度的向量到棋盘坐标和从棋盘坐标到向量之间的位置转换,这只需要查一个长度5的表就可以了。嗯,最终的棋型表示形式肯定要增加一些其他元素,例如前面说的坐标,例如当前棋型属于黑棋还是白棋。
好了,这次的更新没有代码,只是把想法写在这里。因为我还有几个逻辑问题不是很清楚,所以代码还没有写完。过些天我会发布这个版本的新的代码,当然时间可能要长一些,因为最近忙嘛!这个借口不错……希望新的代码能使棋力有一定的提升,因为打算按照我们开始时说的方法来更新招法排序和生成函数。感觉这种方法比较靠近另一种方式的引擎。
今天完成了新的棋盘表示方法和一些算法,默认debug设置在E5200上(单线程)可以达到每秒运行剪裁函数90000次左右,一般都在80000-100000之间。速度还算可以。如果使用置换表的话,速度还会快很多,应该说速度还能令人满意。但是在局面评价上或者剪裁上还有一些问题,可能要剪裁到上一步去才能解决(还没有时间仔细查找代码当中的问题,但是按照设想改了几次局面评价函数和棋型分值都没能解决比对方晚一步胜利却以为自己胜利了,这程序真愚,比我还愚。而且从下面的输出结果来看,某些层上存在一些意外情况,应该是和分值设置有关,也可以从综合分值来解决这些问题,暂时还没有改的打算)。也就是说程序到现在还有一些问题。至于搜索深度,一般达到6-7也就是说树上一般有5个节点左右。以下是输出的一个结果(AI执黑,下7,7,白下8,6时的搜索)
正在迭代:1
已经迭代:1共搜索 31 最佳招法 96 最佳分值 133耗时 0
正在迭代:2
已经迭代:2共搜索 182 最佳招法 128 最佳分值 -3耗时 0
正在迭代:3
已经迭代:3共搜索 3582 最佳招法 142 最佳分值 135耗时 31
正在迭代:4
已经迭代:4共搜索 13145 最佳招法 113 最佳分值 -10耗时 110
正在迭代:5
已经迭代:5共搜索 58703 最佳招法 82 最佳分值 235耗时 500
正在迭代:6
已经迭代:6共搜索 257445 最佳招法 114 最佳分值 80耗时 2204
耗时(毫秒): 2875
迭代加深: 6
置换表命中: 0
共搜索局面: 257445
本次搜索局面: 257445
最多步数: 12
走法路径: bestmove 9,7 ponder 6,7 moveline 9,7 6,6 2,2 1,1 8,7 7,9 6,6
最终分值: 80
最佳走法: 114
搜索速度: 89081.3148788927
下面公开一下源码:呃……怎么code那里光出错。。。。
Public Class mShapes
Private list As New List(Of mShape)
Sub New()
list.Add(New mShape(New Byte() {0, 0, 0, 0, 0}, mConstValue.LinkType.l50))
list.Add(New mShape(New Byte() {0, 0, 0, 0, 1}, 0))
list.Add(New mShape(New Byte() {0, 0, 0, 0, 2}, mConstValue.LinkType.l41))
list.Add(New mShape(New Byte() {0, 0, 0, 1, 0}, 0))
list.Add(New mShape(New Byte() {0, 0, 0, 1, 1}, 0))
list.Add(New mShape(New Byte() {0, 0, 0, 1, 2}, 0))
list.Add(New mShape(New Byte() {0, 0, 0, 2, 0}, mConstValue.LinkType.l41))
list.Add(New mShape(New Byte() {0, 0, 0, 2, 1}, 0))
list.Add(New mShape(New Byte() {0, 0, 0, 2, 2}, mConstValue.LinkType.l31))
list.Add(New mShape(New Byte() {0, 0, 1, 0, 0}, 0))
list.Add(New mShape(New Byte() {0, 0, 1, 0, 1}, 0))
list.Add(New mShape(New Byte() {0, 0, 1, 0, 2}, 0))
list.Add(New mShape(New Byte() {0, 0, 1, 1, 0}, 0))
list.Add(New mShape(New Byte() {0, 0, 1, 1, 1}, 0))
list.Add(New mShape(New Byte() {0, 0, 1, 1, 2}, 0))
list.Add(New mShape(New Byte() {0, 0, 1, 2, 0}, 0))
list.Add(New mShape(New Byte() {0, 0, 1, 2, 1}, 0))
list.Add(New mShape(New Byte() {0, 0, 1, 2, 2}, 0))
list.Add(New mShape(New Byte() {0, 0, 2, 0, 0}, mConstValue.LinkType.l41))
list.Add(New mShape(New Byte() {0, 0, 2, 0, 1}, 0))
list.Add(New mShape(New Byte() {0, 0, 2, 0, 2}, mConstValue.LinkType.l31))
list.Add(New mShape(New Byte() {0, 0, 2, 1, 0}, 0))
list.Add(New mShape(New Byte() {0, 0, 2, 1, 1}, 0))
list.Add(New mShape(New Byte() {0, 0, 2, 1, 2}, 0))
list.Add(New mShape(New Byte() {0, 0, 2, 2, 0}, mConstValue.LinkType.l31))
list.Add(New mShape(New Byte() {0, 0, 2, 2, 1}, 0))
list.Add(New mShape(New Byte() {0, 0, 2, 2, 2}, mConstValue.LinkType.l21))
list.Add(New mShape(New Byte() {0, 1, 0, 0, 0}, 0))
list.Add(New mShape(New Byte() {0, 1, 0, 0, 1}, 0))
list.Add(New mShape(New Byte() {0, 1, 0, 0, 2}, 0))
list.Add(New mShape(New Byte() {0, 1, 0, 1, 0}, 0))
list.Add(New mShape(New Byte() {0, 1, 0, 1, 1}, 0))
list.Add(New mShape(New Byte() {0, 1, 0, 1, 2}, 0))
list.Add(New mShape(New Byte() {0, 1, 0, 2, 0}, 0))
list.Add(New mShape(New Byte() {0, 1, 0, 2, 1}, 0))
list.Add(New mShape(New Byte() {0, 1, 0, 2, 2}, 0))
list.Add(New mShape(New Byte() {0, 1, 1, 0, 0}, 0))
list.Add(New mShape(New Byte() {0, 1, 1, 0, 1}, 0))
list.Add(New mShape(New Byte() {0, 1, 1, 0, 2}, 0))
list.Add(New mShape(New Byte() {0, 1, 1, 1, 0}, 0))
list.Add(New mShape(New Byte() {0, 1, 1, 1, 1}, 0))
list.Add(New mShape(New Byte() {0, 1, 1, 1, 2}, 0))
list.Add(New mShape(New Byte() {0, 1, 1, 2, 0}, 0))
list.Add(New mShape(New Byte() {0, 1, 1, 2, 1}, 0))
list.Add(New mShape(New Byte() {0, 1, 1, 2, 2}, 0))
list.Add(New mShape(New Byte() {0, 1, 2, 0, 0}, 0))
list.Add(New mShape(New Byte() {0, 1, 2, 0, 1}, 0))
list.Add(New mShape(New Byte() {0, 1, 2, 0, 2}, 0))
list.Add(New mShape(New Byte() {0, 1, 2, 1, 0}, 0))
list.Add(New mShape(New Byte() {0, 1, 2, 1, 1}, 0))
list.Add(New mShape(New Byte() {0, 1, 2, 1, 2}, 0))
list.Add(New mShape(New Byte() {0, 1, 2, 2, 0}, 0))
list.Add(New mShape(New Byte() {0, 1, 2, 2, 1}, 0))
list.Add(New mShape(New Byte() {0, 1, 2, 2, 2}, 0))
list.Add(New mShape(New Byte() {0, 2, 0, 0, 0}, mConstValue.LinkType.l41))
list.Add(New mShape(New Byte() {0, 2, 0, 0, 1}, 0))
list.Add(New mShape(New Byte() {0, 2, 0, 0, 2}, mConstValue.LinkType.l31))
list.Add(New mShape(New Byte() {0, 2, 0, 1, 0}, 0))
list.Add(New mShape(New Byte() {0, 2, 0, 1, 1}, 0))
list.Add(New mShape(New Byte() {0, 2, 0, 1, 2}, 0))
list.Add(New mShape(New Byte() {0, 2, 0, 2, 0}, mConstValue.LinkType.l31))
list.Add(New mShape(New Byte() {0, 2, 0, 2, 1}, 0))
list.Add(New mShape(New Byte() {0, 2, 0, 2, 2}, mConstValue.LinkType.l21))
list.Add(New mShape(New Byte() {0, 2, 1, 0, 0}, 0))
list.Add(New mShape(New Byte() {0, 2, 1, 0, 1}, 0))
list.Add(New mShape(New Byte() {0, 2, 1, 0, 2}, 0))
list.Add(New mShape(New Byte() {0, 2, 1, 1, 0}, 0))
list.Add(New mShape(New Byte() {0, 2, 1, 1, 1}, 0))
list.Add(New mShape(New Byte() {0, 2, 1, 1, 2}, 0))
list.Add(New mShape(New Byte() {0, 2, 1, 2, 0}, 0))
list.Add(New mShape(New Byte() {0, 2, 1, 2, 1}, 0))
list.Add(New mShape(New Byte() {0, 2, 1, 2, 2}, 0))
list.Add(New mShape(New Byte() {0, 2, 2, 0, 0}, mConstValue.LinkType.l31))
list.Add(New mShape(New Byte() {0, 2, 2, 0, 1}, 0))
list.Add(New mShape(New Byte() {0, 2, 2, 0, 2}, mConstValue.LinkType.l21))
list.Add(New mShape(New Byte() {0, 2, 2, 1, 0}, 0))
list.Add(New mShape(New Byte() {0, 2, 2, 1, 1}, 0))
list.Add(New mShape(New Byte() {0, 2, 2, 1, 2}, 0))
list.Add(New mShape(New Byte() {0, 2, 2, 2, 0}, mConstValue.LinkType.l20))
list.Add(New mShape(New Byte() {0, 2, 2, 2, 1}, 0))
list.Add(New mShape(New Byte() {0, 2, 2, 2, 2}, mConstValue.LinkType.l11))
list.Add(New mShape(New Byte() {1, 0, 0, 0, 0}, 0))
list.Add(New mShape(New Byte() {1, 0, 0, 0, 1}, 0))
list.Add(New mShape(New Byte() {1, 0, 0, 0, 2}, 0))
list.Add(New mShape(New Byte() {1, 0, 0, 1, 0}, 0))
list.Add(New mShape(New Byte() {1, 0, 0, 1, 1}, 0))
list.Add(New mShape(New Byte() {1, 0, 0, 1, 2}, 0))
list.Add(New mShape(New Byte() {1, 0, 0, 2, 0}, 0))
list.Add(New mShape(New Byte() {1, 0, 0, 2, 1}, 0))
list.Add(New mShape(New Byte() {1, 0, 0, 2, 2}, 0))
list.Add(New mShape(New Byte() {1, 0, 1, 0, 0}, 0))
list.Add(New mShape(New Byte() {1, 0, 1, 0, 1}, 0))
list.Add(New mShape(New Byte() {1, 0, 1, 0, 2}, 0))
list.Add(New mShape(New Byte() {1, 0, 1, 1, 0}, 0))
list.Add(New mShape(New Byte() {1, 0, 1, 1, 1}, 0))
list.Add(New mShape(New Byte() {1, 0, 1, 1, 2}, 0))
list.Add(New mShape(New Byte() {1, 0, 1, 2, 0}, 0))
list.Add(New mShape(New Byte() {1, 0, 1, 2, 1}, 0))
list.Add(New mShape(New Byte() {1, 0, 1, 2, 2}, 0))
list.Add(New mShape(New Byte() {1, 0, 2, 0, 0}, 0))
list.Add(New mShape(New Byte() {1, 0, 2, 0, 1}, 0))
list.Add(New mShape(New Byte() {1, 0, 2, 0, 2}, 0))
list.Add(New mShape(New Byte() {1, 0, 2, 1, 0}, 0))
list.Add(New mShape(New Byte() {1, 0, 2, 1, 1}, 0))
list.Add(New mShape(New Byte() {1, 0, 2, 1, 2}, 0))
list.Add(New mShape(New Byte() {1, 0, 2, 2, 0}, 0))
list.Add(New mShape(New Byte() {1, 0, 2, 2, 1}, 0))
list.Add(New mShape(New Byte() {1, 0, 2, 2, 2}, 0))
list.Add(New mShape(New Byte() {1, 1, 0, 0, 0}, 0))
list.Add(New mShape(New Byte() {1, 1, 0, 0, 1}, 0))
list.Add(New mShape(New Byte() {1, 1, 0, 0, 2}, 0))
list.Add(New mShape(New Byte() {1, 1, 0, 1, 0}, 0))
list.Add(New mShape(New Byte() {1, 1, 0, 1, 1}, 0))
list.Add(New mShape(New Byte() {1, 1, 0, 1, 2}, 0))
list.Add(New mShape(New Byte() {1, 1, 0, 2, 0}, 0))
list.Add(New mShape(New Byte() {1, 1, 0, 2, 1}, 0))
list.Add(New mShape(New Byte() {1, 1, 0, 2, 2}, 0))
list.Add(New mShape(New Byte() {1, 1, 1, 0, 0}, 0))
list.Add(New mShape(New Byte() {1, 1, 1, 0, 1}, 0))
list.Add(New mShape(New Byte() {1, 1, 1, 0, 2}, 0))
list.Add(New mShape(New Byte() {1, 1, 1, 1, 0}, 0))
list.Add(New mShape(New Byte() {1, 1, 1, 1, 1}, mConstValue.LinkType.l50))
list.Add(New mShape(New Byte() {1, 1, 1, 1, 2}, mConstValue.LinkType.l41))
list.Add(New mShape(New Byte() {1, 1, 1, 2, 0}, 0))
list.Add(New mShape(New Byte() {1, 1, 1, 2, 1}, mConstValue.LinkType.l41))
list.Add(New mShape(New Byte() {1, 1, 1, 2, 2}, mConstValue.LinkType.l31))
list.Add(New mShape(New Byte() {1, 1, 2, 0, 0}, 0))
list.Add(New mShape(New Byte() {1, 1, 2, 0, 1}, 0))
list.Add(New mShape(New Byte() {1, 1, 2, 0, 2}, 0))
list.Add(New mShape(New Byte() {1, 1, 2, 1, 0}, 0))
list.Add(New mShape(New Byte() {1, 1, 2, 1, 1}, mConstValue.LinkType.l41))
list.Add(New mShape(New Byte() {1, 1, 2, 1, 2}, mConstValue.LinkType.l31))
list.Add(New mShape(New Byte() {1, 1, 2, 2, 0}, 0))
list.Add(New mShape(New Byte() {1, 1, 2, 2, 1}, mConstValue.LinkType.l31))
list.Add(New mShape(New Byte() {1, 1, 2, 2, 2}, mConstValue.LinkType.l21))
list.Add(New mShape(New Byte() {1, 2, 0, 0, 0}, 0))
list.Add(New mShape(New Byte() {1, 2, 0, 0, 1}, 0))
list.Add(New mShape(New Byte() {1, 2, 0, 0, 2}, 0))
list.Add(New mShape(New Byte() {1, 2, 0, 1, 0}, 0))
list.Add(New mShape(New Byte() {1, 2, 0, 1, 1}, 0))
list.Add(New mShape(New Byte() {1, 2, 0, 1, 2}, 0))
list.Add(New mShape(New Byte() {1, 2, 0, 2, 0}, 0))
list.Add(New mShape(New Byte() {1, 2, 0, 2, 1}, 0))
list.Add(New mShape(New Byte() {1, 2, 0, 2, 2}, 0))
list.Add(New mShape(New Byte() {1, 2, 1, 0, 0}, 0))
list.Add(New mShape(New Byte() {1, 2, 1, 0, 1}, 0))
list.Add(New mShape(New Byte() {1, 2, 1, 0, 2}, 0))
list.Add(New mShape(New Byte() {1, 2, 1, 1, 0}, 0))
list.Add(New mShape(New Byte() {1, 2, 1, 1, 1}, mConstValue.LinkType.l41))
list.Add(New mShape(New Byte() {1, 2, 1, 1, 2}, mConstValue.LinkType.l31))
list.Add(New mShape(New Byte() {1, 2, 1, 2, 0}, 0))
list.Add(New mShape(New Byte() {1, 2, 1, 2, 1}, mConstValue.LinkType.l31))
list.Add(New mShape(New Byte() {1, 2, 1, 2, 2}, mConstValue.LinkType.l21))
list.Add(New mShape(New Byte() {1, 2, 2, 0, 0}, 0))
list.Add(New mShape(New Byte() {1, 2, 2, 0, 1}, 0))
list.Add(New mShape(New Byte() {1, 2, 2, 0, 2}, 0))
list.Add(New mShape(New Byte() {1, 2, 2, 1, 0}, 0))
list.Add(New mShape(New Byte() {1, 2, 2, 1, 1}, mConstValue.LinkType.l31))
list.Add(New mShape(New Byte() {1, 2, 2, 1, 2}, mConstValue.LinkType.l21))
list.Add(New mShape(New Byte() {1, 2, 2, 2, 0}, 0))
list.Add(New mShape(New Byte() {1, 2, 2, 2, 1}, mConstValue.LinkType.l20))
list.Add(New mShape(New Byte() {1, 2, 2, 2, 2}, mConstValue.LinkType.l11))
list.Add(New mShape(New Byte() {2, 0, 0, 0, 0}, mConstValue.LinkType.l41))
list.Add(New mShape(New Byte() {2, 0, 0, 0, 1}, 0))
list.Add(New mShape(New Byte() {2, 0, 0, 0, 2}, mConstValue.LinkType.l32))
list.Add(New mShape(New Byte() {2, 0, 0, 1, 0}, 0))
list.Add(New mShape(New Byte() {2, 0, 0, 1, 1}, 0))
list.Add(New mShape(New Byte() {2, 0, 0, 1, 2}, 0))
list.Add(New mShape(New Byte() {2, 0, 0, 2, 0}, mConstValue.LinkType.l31))
list.Add(New mShape(New Byte() {2, 0, 0, 2, 1}, 0))
list.Add(New mShape(New Byte() {2, 0, 0, 2, 2}, mConstValue.LinkType.l22))
list.Add(New mShape(New Byte() {2, 0, 1, 0, 0}, 0))
list.Add(New mShape(New Byte() {2, 0, 1, 0, 1}, 0))
list.Add(New mShape(New Byte() {2, 0, 1, 0, 2}, 0))
list.Add(New mShape(New Byte() {2, 0, 1, 1, 0}, 0))
list.Add(New mShape(New Byte() {2, 0, 1, 1, 1}, 0))
list.Add(New mShape(New Byte() {2, 0, 1, 1, 2}, 0))
list.Add(New mShape(New Byte() {2, 0, 1, 2, 0}, 0))
list.Add(New mShape(New Byte() {2, 0, 1, 2, 1}, 0))
list.Add(New mShape(New Byte() {2, 0, 1, 2, 2}, 0))
list.Add(New mShape(New Byte() {2, 0, 2, 0, 0}, mConstValue.LinkType.l31))
list.Add(New mShape(New Byte() {2, 0, 2, 0, 1}, 0))
list.Add(New mShape(New Byte() {2, 0, 2, 0, 2}, mConstValue.LinkType.l21))
list.Add(New mShape(New Byte() {2, 0, 2, 1, 0}, 0))
list.Add(New mShape(New Byte() {2, 0, 2, 1, 1}, 0))
list.Add(New mShape(New Byte() {2, 0, 2, 1, 2}, 0))
list.Add(New mShape(New Byte() {2, 0, 2, 2, 0}, mConstValue.LinkType.l21))
list.Add(New mShape(New Byte() {2, 0, 2, 2, 1}, 0))
list.Add(New mShape(New Byte() {2, 0, 2, 2, 2}, mConstValue.LinkType.l12))
list.Add(New mShape(New Byte() {2, 1, 0, 0, 0}, 0))
list.Add(New mShape(New Byte() {2, 1, 0, 0, 1}, 0))
list.Add(New mShape(New Byte() {2, 1, 0, 0, 2}, 0))
list.Add(New mShape(New Byte() {2, 1, 0, 1, 0}, 0))
list.Add(New mShape(New Byte() {2, 1, 0, 1, 1}, 0))
list.Add(New mShape(New Byte() {2, 1, 0, 1, 2}, 0))
list.Add(New mShape(New Byte() {2, 1, 0, 2, 0}, 0))
list.Add(New mShape(New Byte() {2, 1, 0, 2, 1}, 0))
list.Add(New mShape(New Byte() {2, 1, 0, 2, 2}, 0))
list.Add(New mShape(New Byte() {2, 1, 1, 0, 0}, 0))
list.Add(New mShape(New Byte() {2, 1, 1, 0, 1}, 0))
list.Add(New mShape(New Byte() {2, 1, 1, 0, 2}, 0))
list.Add(New mShape(New Byte() {2, 1, 1, 1, 0}, 0))
list.Add(New mShape(New Byte() {2, 1, 1, 1, 1}, mConstValue.LinkType.l41))
list.Add(New mShape(New Byte() {2, 1, 1, 1, 2}, mConstValue.LinkType.l32))
list.Add(New mShape(New Byte() {2, 1, 1, 2, 0}, 0))
list.Add(New mShape(New Byte() {2, 1, 1, 2, 1}, mConstValue.LinkType.l31))
list.Add(New mShape(New Byte() {2, 1, 1, 2, 2}, mConstValue.LinkType.l22))
list.Add(New mShape(New Byte() {2, 1, 2, 0, 0}, 0))
list.Add(New mShape(New Byte() {2, 1, 2, 0, 1}, 0))
list.Add(New mShape(New Byte() {2, 1, 2, 0, 2}, 0))
list.Add(New mShape(New Byte() {2, 1, 2, 1, 0}, 0))
list.Add(New mShape(New Byte() {2, 1, 2, 1, 1}, mConstValue.LinkType.l31))
list.Add(New mShape(New Byte() {2, 1, 2, 1, 2}, mConstValue.LinkType.l22))
list.Add(New mShape(New Byte() {2, 1, 2, 2, 0}, 0))
list.Add(New mShape(New Byte() {2, 1, 2, 2, 1}, mConstValue.LinkType.l21))
list.Add(New mShape(New Byte() {2, 1, 2, 2, 2}, mConstValue.LinkType.l12))
list.Add(New mShape(New Byte() {2, 2, 0, 0, 0}, mConstValue.LinkType.l31))
list.Add(New mShape(New Byte() {2, 2, 0, 0, 1}, 0))
list.Add(New mShape(New Byte() {2, 2, 0, 0, 2}, mConstValue.LinkType.l22))
list.Add(New mShape(New Byte() {2, 2, 0, 1, 0}, 0))
list.Add(New mShape(New Byte() {2, 2, 0, 1, 1}, 0))
list.Add(New mShape(New Byte() {2, 2, 0, 1, 2}, 0))
list.Add(New mShape(New Byte() {2, 2, 0, 2, 0}, mConstValue.LinkType.l21))
list.Add(New mShape(New Byte() {2, 2, 0, 2, 1}, 0))
list.Add(New mShape(New Byte() {2, 2, 0, 2, 2}, mConstValue.LinkType.l12))
list.Add(New mShape(New Byte() {2, 2, 1, 0, 0}, 0))
list.Add(New mShape(New Byte() {2, 2, 1, 0, 1}, 0))
list.Add(New mShape(New Byte() {2, 2, 1, 0, 2}, 0))
list.Add(New mShape(New Byte() {2, 2, 1, 1, 0}, 0))
list.Add(New mShape(New Byte() {2, 2, 1, 1, 1}, mConstValue.LinkType.l31))
list.Add(New mShape(New Byte() {2, 2, 1, 1, 2}, mConstValue.LinkType.l22))
list.Add(New mShape(New Byte() {2, 2, 1, 2, 0}, 0))
list.Add(New mShape(New Byte() {2, 2, 1, 2, 1}, mConstValue.LinkType.l21))
list.Add(New mShape(New Byte() {2, 2, 1, 2, 2}, mConstValue.LinkType.l12))
list.Add(New mShape(New Byte() {2, 2, 2, 0, 0}, mConstValue.LinkType.l21))
list.Add(New mShape(New Byte() {2, 2, 2, 0, 1}, 0))
list.Add(New mShape(New Byte() {2, 2, 2, 0, 2}, mConstValue.LinkType.l12))
list.Add(New mShape(New Byte() {2, 2, 2, 1, 0}, 0))
list.Add(New mShape(New Byte() {2, 2, 2, 1, 1}, mConstValue.LinkType.l31))
list.Add(New mShape(New Byte() {2, 2, 2, 1, 2}, mConstValue.LinkType.l12))
list.Add(New mShape(New Byte() {2, 2, 2, 2, 0}, mConstValue.LinkType.l11))
list.Add(New mShape(New Byte() {2, 2, 2, 2, 1}, mConstValue.LinkType.l11))
list.Add(New mShape(New Byte() {2, 2, 2, 2, 2}, 0))
'下面初始化转换结果
For i As Integer = 0 To list.Count - 1 '遍历list,对每个模型进行查找
Dim lm As mShape = list(i)
Dim bk As Byte '原始值备份
For j As Integer = 0 To 4 '5个点
For k As Integer = 0 To 2 '3种值
If lm.PointValues(j) = k Then '若转换后是自身
lm.sMod(j * 3 + k) = Nothing
Else
bk = lm.PointValues(j) '取原始值
lm.PointValues(j) = k '替换
For l As Integer = 0 To list.Count - 1 '遍历list,查找与之一致的模型
If i <> l Then '不能是自身
Dim tk As mShape = list(l)
If lm.Equals(tk) Then
lm.sMod(j * 3 + k) = tk '将一致模型记录下来
Exit For
End If
End If
Next
lm.PointValues(j) = bk '恢复原始值
End If
Next
Next
Next
End Sub
'获取设置指定点上的棋子后转化成的形态
Public Function NextShape(mlmd As mShape, point As Integer, player As Integer) As mShape
Return mlmd.sMod(point * 3 + player)
End Function
'默认形态
Public Function defShape() As mShape
Return list(242)
End Function
End Class
Public Class mShape
Public PointValues(4) As Integer '各点棋子(0=无子,1=己方,2=对方)。
Public sMod(14) As mShape '转换结果
Public Player As Integer '所属玩家
Public type As mConstValue.LinkType '棋型类型
Sub New(pvs() As Byte, tp As mConstValue.LinkType)
Dim i, w, b As Integer
For i = 0 To 4
PointValues(i) = pvs(i)
If pvs(i) = 0 Then
w += 1
ElseIf pvs(i) = 1 Then
b += 1
End If
Next
Player = 2
If w = 0 AndAlso b > 0 Then Player = 1
If w > 0 AndAlso b = 0 Then Player = 0
type = tp
End Sub
Public Overrides Function Equals(obj As Object) As Boolean
Dim tmp As mShape = obj
Return tmp.PointValues(0) = Me.PointValues(0) AndAlso tmp.PointValues(1) = Me.PointValues(1) AndAlso tmp.PointValues(2) = Me.PointValues(2) AndAlso tmp.PointValues(3) = Me.PointValues(3) AndAlso tmp.PointValues(4) = Me.PointValues(4)
End Function
End Class
这样贴出来不太整齐。这就是核心的代码了,前面已经说过,五子棋是棋型转换,无论是下子还是提子,一次一个,所以变化之后的结果是完全可以预知的,无需去识别。存储棋型的lsit的代码是写了一段程序自动生成的,当然了,分值是改上去的好像是七十几个。代码没有什么难的地方。接下来就是把以前代码中的14长度的向量,拆分成5长度的向量,记录每个点对应的向量。这样一来,我们完全可以在addpipe函数和delpipe函数运行时提高极大:用一个数组来记录5,冲4,活3,冲3,活2,冲2包含的向量,变化时直接从上面的类取结果,评价时直接取那些向量的分值即可,而走法生成无需排序,从冲4开始向下生成就可以了(之所以我输出的结果中只有5个节点左右,是因为只取了2层冲棋情况,实际上最近打算使用完全搜索结合棋型剪裁来尝试一下,不过有些地方还比较懵懂)。当然,由于我们的向量长度只有5,所以没有活4,而且一个点对应的向量有若干个,生成时需要用一个表来记录哪些点已经添加(不要去读返回值数组,用一个bitarray记录速度更快)。
好了,今天就写到这里。等再有时间把剪裁的问题解决好再写下一篇。希望这个五子棋棋盘数据结构能够给大家一些启迪。欢迎高手指导!
全部文章和源码整理完成,以后更新也会在下面地址: