


[bili=5840786]1[/bili]
下页原理讲解目录
下页——从五子棋谈起



如图,在我的作品中,一个点周围八个方向的四个点被认为是值得考虑的,而极速版与Beta版的区别在于——极速版只把黑白双方最近两手类似这样的扩展情况所扩展出来的点作为待选点,而Beta版则是将所有点进行这样的延伸,延伸到的空点都可能被选中。这样各有优劣,如果采取前者的方式,那么也会有可能漏掉一些有用的点,举个例子,如果白棋也就是电脑不断冲四(一头被黑棋堵住,另外一头连成了4个),这时黑棋就要不断去堵,当两回合过后,如果前几次冲四的延伸点离黑棋有威胁的点(双头都没被白棋堵住的三个黑棋)很远,那么系统就会认为挡住黑棋的那两个点是无意义的,不作为待选,自然我的AI就败北了。而Beta版因为每个点都这样延伸,就不会出现问题,但是由于待选点增多,系统就会比极速版卡一些,有利有弊吧。
那么,下面来看看两种做法如何实现吧,首先是只考虑最近两回合的:
首先在屏幕的后面,在玩家落子的位置会生成一个名叫Black的AEC(AreaEffectCloud,中文名药水云,作实体标记用),这样就能以这个点为中心进行延伸了。
- /summon AreaEffectCloud ~ ~ ~2 {Duration:2100000000,CustomName:"Black"}
- /execute @e[type=AreaEffectCloud,name=Black] ~ ~ ~ /summon AreaEffectCloud ~1 ~ ~ {Duration:2100000000,CustomName:"Indeterminate",Tags:["Not"]}
接下来对目前刷出来的所有待选点+1s
- /scoreboard players add @e[name=Indeterminate,type=AreaEffectCloud] Repeat 1
- /execute @e[type=AreaEffectCloud,name=White] ~ ~ ~ /summon AreaEffectCloud ~1 ~ ~ {Duration:2100000000,CustomName:"Indeterminate",Tags:["Not"]}
- /kill @e[name=White,type=AreaEffectCloud]
- /scoreboard players add @e[name=Indeterminate,type=AreaEffectCloud] Repeat 1
- /execute @e[score_Repeat_min=2,score_Repeat=2] ~ ~ ~ /kill @e[type=AreaEffectCloud,name=Indeterminate,dx=0,dy=0,dz=0,score_Repeat_min=1,score_Repeat=1]
- /scoreboard players set @e[score_Repeat_min=1,score_Repeat=2] Repeat 0
- /scoreboard players remove @e[score_Repeat_min=3,score_Repeat=4] Repeat 2
先给本来就有棋子的地方的待选点赐死:
- /execute @e[type=AreaEffectCloud,name=Indeterminate] ~ ~ ~ detect ~ ~ ~ wool 0 /kill @e[c=1,type=AreaEffectCloud,name=Indeterminate]
- /execute @e[type=AreaEffectCloud,name=Indeterminate] ~ ~ ~ detect ~ ~ ~ wool 15 /kill @e[c=1,type=AreaEffectCloud,name=Indeterminate]
- /execute @e[type=AreaEffectCloud,name=Indeterminate] ~ ~ ~ detect ~ ~ ~-1 end_stone 0 /scoreboard players tag @e[c=1,type=AreaEffectCloud,name=Indeterminate] remove Not
- /kill @e[type=AreaEffectCloud,name=Indeterminate,tag=Not]
- /scoreboard players tag @e[type=AreaEffectCloud,name=Indeterminate] add Not
- /scoreboard players add @e[name=Indeterminate,type=AreaEffectCloud] Repeat 1
- /kill @e[score_Repeat_min=3]
- /execute @e[score_Repeat_min=1,score_Repeat=1] ~ ~ ~ /kill @e[score_Repeat_min=2,score_Repeat=2,dx=0,dy=0,dz=0]
下页——基础搜索

现在以红色玻璃那个待选点为例,它的一号五元组就是普通玻璃的那五个,从这个点的~ ~-4 ~到这个待选点本身的位置(我这里会再往上TP一格但不会执行指令,所以相对位置就是~ ~-1 ~),那么就知道,所有待选点的一号五元组最后的位置就是待选点的位置(从~ ~-4 ~ 开始往上探测),这样大家都能各司其职而不乱套了。还是以一号五元组为例,看看具体的实现方式,其他方法类似就不多啰嗦了:
五元组编号分别是从Testfor1-Testfor20,由于要先对所有本待选点负责的五元组全部重置分数而不影响别的待选点,先一致在待选点位置刷出,重置完分数以后再分配到岗位上
- /execute @e[type=AreaEffectCloud,name=Indeterminate] ~ ~ ~ /summon AreaEffectCloud ~ ~ ~ {Duration:2100000000,CustomName:"Testfor"}
- /execute @e[type=AreaEffectCloud,name=Indeterminate] ~ ~ ~ /scoreboard players set @e[type=AreaEffectCloud,dx=0,dy=0,dz=0] Black 0
- /execute @e[type=AreaEffectCloud,name=Indeterminate] ~ ~ ~ /scoreboard players set @e[type=AreaEffectCloud,dx=0,dy=0,dz=0] White 0
- /execute @e[type=AreaEffectCloud,name=Indeterminate] ~ ~ ~ /scoreboard players set @e[type=AreaEffectCloud,dx=0,dy=0,dz=0] Barrier 0
- /tp @e[type=AreaEffectCloud,name=Testfor] ~ ~-4 ~
下面这些命令都是会被执行五次的:
这些就是对当前AEC所在的位置进行扫描
- /execute @e[type=AreaEffectCloud,name=Testfor] ~ ~ ~ detect ~ ~ ~ wool 0 /scoreboard players add @e[type=AreaEffectCloud,name=Testfor,c=1,r=0] White 1
- /tp @e[type=AreaEffectCloud,name=Testfor] ~ ~1 ~
- /execute @e[type=AreaEffectCloud,name=Testfor,score_Black_min=4,score_Black=4,score_White=0,score_Barrier=0] ~ ~-1 ~ /scoreboard players add @e[r=0,type=AreaEffectCloud,name=Indeterminate,c=1] Score 100000
- /execute @e[type=AreaEffectCloud,name=Testfor,score_Black_min=3,score_Black=3,score_White=0,score_Barrier=0] ~ ~-1 ~ /scoreboard players add @e[r=0,type=AreaEffectCloud,name=Indeterminate,c=1] Score 1800
- /execute @e[type=AreaEffectCloud,name=Testfor,score_Black_min=2,score_Black=2,score_White=0,score_Barrier=0] ~ ~-1 ~ /scoreboard players add @e[r=0,type=AreaEffectCloud,name=Indeterminate,c=1] Score 400
- /execute @e[type=AreaEffectCloud,name=Testfor,score_Black_min=1,score_Black=1,score_White=0,score_Barrier=0] ~ ~-1 ~ /scoreboard players add @e[r=0,type=AreaEffectCloud,name=Indeterminate,c=1] Score 15
- /execute @e[type=AreaEffectCloud,name=Testfor,score_White_min=1,score_White=1,score_Black=0,score_Barrier=0] ~ ~-1 ~ /scoreboard players add @e[r=0,type=AreaEffectCloud,name=Indeterminate,c=1] Score 35
- /execute @e[type=AreaEffectCloud,name=Testfor,score_White_min=2,score_White=2,score_Black=0,score_Barrier=0] ~ ~-1 ~ /scoreboard players add @e[r=0,type=AreaEffectCloud,name=Indeterminate,c=1] Score 800
- /execute @e[type=AreaEffectCloud,name=Testfor,score_White_min=3,score_White=3,score_Black=0,score_Barrier=0] ~ ~-1 ~ /scoreboard players add @e[r=0,type=AreaEffectCloud,name=Indeterminate,c=1] Score 15000
- /execute @e[type=AreaEffectCloud,name=Testfor,score_White_min=4,score_White=4,score_Black=0,score_Barrier=0] ~ ~-1 ~ /scoreboard players add @e[r=0,type=AreaEffectCloud,name=Indeterminate,c=1] Score 800000
- /execute @e[type=AreaEffectCloud,name=Testfor,score_White_min=1,score_Black_min=1,score_Barrier=0] ~ ~-1 ~ /scoreboard players add @e[r=0,type=AreaEffectCloud,name=Indeterminate,c=1] Score 0
- /execute @e[type=AreaEffectCloud,name=Testfor,score_White=0,score_Black=0,score_Barrier=0] ~ ~-1 ~ /scoreboard players add @e[r=0,type=AreaEffectCloud,name=Indeterminate,c=1] Score 7
- /execute @e[type=AreaEffectCloud,name=Testfor,score_Barrier_min=1] ~ ~-1 ~ /scoreboard players add @e[r=0,type=AreaEffectCloud,name=Indeterminate,c=1] Score 0
- /kill @e[type=AreaEffectCloud,name=Testfor]
- ......
这里说一下,极速版就是取这些点分数最高的那个落子,而Beta版还需要对这些分数的第一名和第二名进行深度搜索,原理类似,就贴极速版的命令了。
其实就是用了计分板的>,与帖子核心内容没啥大关系,就不解释了。
- /summon AreaEffectCloud ~ ~ ~ {Duration:2100000000,CustomName:"Holder"}[indent]/scoreboard players operation @e[name=Holder,type=AreaEffectCloud,c=1] Score > @e[name=Indeterminate,type=AreaEffectCloud] Score[/indent]/scoreboard players operation @e[type=AreaEffectCloud,name=Indeterminate] Score -= @e[type=AreaEffectCloud,name=Holder,c=1] Score
下页——深度搜索
所谓深度搜索,其实就是对基础搜索选出的点进行模拟推演一遍,然后对推演出的局面进行分析到底孰优孰劣再决定选谁落子。我这里采取的方式是模拟白棋落子之后黑棋落子之后的局面情况,说白了就是预判一回合的意思,没那么深奥。就以基础搜索的图为例:

在这种局面下,白棋最优和次优的点分别是这两个点

那么系统就会模拟白棋落子在这两个点,然后又模拟黑棋会如何应对,对黑棋应招后的局面进行分析。值得一提的是,黑棋应对的棋形权重就是刚才的那个权重,只是把黑白倒置而已,例如AI执白的时候四个黑是10w分,四个白是80w分,现在AI(模拟)执黑,四个黑就是80w分,四个白就是10w分。方法就是基础搜索的方法,这里不再赘述,就说一下黑棋落子之后我是如何对当前局面(推演一回合后的局面)做出评价的。

假设白棋走了左边堵并且自己连成三个,这时黑棋选择连成四个吓唬一下,我们就会对以白棋落子为中心和黑棋应着为中心的点做米字形发散(参见待选点是如何炼成的),但是我这次是直接放置红石块在后面的一块刷出屏幕上,就省了去重的麻烦了。

但是要注意的是,这次生成的点是不会因为这个点有方块而杀死自己的,因为我们是局面评价,如果杀死有棋子的点会出现这样尴尬的情况:

黑棋走黑色玻璃获胜,可米字格探测却全部被杀死(因为都有方块),就探测不到如此劣势。
然后就是对这些米字形的点给一个分数,但是与之前不同的是,这次给的是相对于电脑的优(劣)势分数,如果这个分数是正,就代表电脑在这个点上有优势,如果是负,电脑自然有劣势。其实就是把前面的评分表进行微调,在这就只列出调整的部分:
五元组内有五个白,无黑子——8000000分
五元组内有五个黑,无白子——4000000分
五元组内有三个白,无黑子——2400分
然后对所有点的相对优势分数相加就得到这个局面的相对优势分数,选相对优势分数大的那个局面的白棋走法落子(或者说相对劣势小),有兴趣的朋友不妨算一下,下面这种局面的分数和之前自己连成三个的局面哪个分数大,答案不言自明。

那么,就可以落子了。
下页——展望
其实,五子棋AI依然有很大的改进空间,在这里举出一个可行的方案——对同样棋子个数时不同棋子的排布情况优化评分,比如

上下两种棋子虽然都是三个,但是评分仍然是可以优化的,针对五元组内棋子的顺序,你可以在五次执行中间再加入一个储存位置的计分板,然后综合判定,虽然这样会比较麻烦,但是智商无疑是能得到很好提升的,穷举狂不妨试试(笑
人工智能特别是下棋,的确是一个很玄学的东西,没有绝对好和绝对坏的算法,但是真正属于你的是——搭建作品时的那份感动,测试时的紧张与成功的喜悦,这真的只是个载体。
来自群组:The Minecraft Lover

