有禁手五子棋,黑棋下在这里,形成横四竖三局势,符合规定吗?

刚刚写完了第4个程序,实现了迭代加深、空步剪裁、冲棋延伸。(棋盘剪裁已经在第3个程序里面实现了)。本来准备写第5个程序,不过有点累了,就没有继续写。后面几篇更新的速度会慢一些,主要是写完之后我还需要仔细检查一下,这样一个程序尤其是偌大一个递归函数里面搞来搞去的,难免出现一些问题,尤其是手误,逻辑怎么看都没问题,又处于递归当中很难调试查找。为了示例程序尽可能少的出现问题,我会进行一定量的测试,当然测试量不可能很大,我还没有写和其他程序下棋的接口,所以无法从大量对局中查找问题和评价程序的真实棋力。

引擎下棋的最基础的东西,就是评价局面。这往往需要大量的对局和校正参数,而我没有做这些工作,原因前面已经说过了。但是不代表我们无法粗略的设置一些分值,尤其是像五子棋这样的程序,评分不是子力,而应该是从“形”“势”角度出发,所以没有固定的子力分值评价和位置分值评价。在我的程序中,是使用模板来进行棋型评价(这和我最初发布的文章当中有所不同,因为经过测试,发现那种方法不仅难于编码和调试,而且速度并不比模板匹配快多少,所以综合起来还是采用了模板评价)的,然后综合这72个评价结果并与对方棋72个结果进行比较来得到分值。原文地址例如,对方有一个冲4,而我们双活3,我们理所应当的去封堵,但是我们能认为双活3的棋力小于冲4吗?当然不。所以我采用了上述的评价方式。具体实现是这样的:

72这个数,是五子棋上的“成棋向量”,只有72个方向能成5,而其他方向不够长度……这么说吧,横向15,纵向15,左下右上21,左上右下21,一共72。

2、如何得到这72个向量?如何记录它们?

得到这些向量很容易,可以硬编码,也可以循环遍历。我才用了循环遍历的方式,因为为了速度更快,我需要记录向量上的每个点,而不是计算它们。——当然,这里我没有进行测试,我感觉,一个14个元素的byte数组寻址速度不会很慢。

其中的hs是一个哈希表,为什么需要这个表呢?因为我们需要知道一个点所在的全部向量,这样我们放一个棋子或删除一个棋子之后,就可以知道哪些向量需要更新评价值,而不是更新全部的向量评价,要知道模板匹配即使使用了内存比较API也非常慢,何况我们是从一个长度可能达到14的信息中遍历若干个模板的位置。当然,现在的做法完全可以进一步优化,但是我准备在发完这些连载之后,再抽时间进行细致的优化或许到时候能够找到更有效更快速的方式。

3、得到向量之后,如何评价?

我们使用一个数组,来记录当前向量上的全部子和空位,而后和模板数组进行比较,从而得到棋型信息。我们不会得到棋型的具体分值,最终综合棋型才得到得分。

实际的评价函数,是一个非常长的函数:

看起来可能非常短,但是实际上……这是因为提取了EvaluateShape函数,这个函数看起来甚至让人憎恶,因为它长得如此丑陋:

事实上,没有一万句那么多,但是加起来模板和模板匹配函数,有几百行了。具体情况还是请各位看代码吧。

4、得到向量的棋型评价和冲棋信息之后,是如何评价局面的?

实际上,局面评价函数也是面目狰狞的……不过幸好线条很清晰:

首先,我们要遍历每个向量,如果需要更新,那么就运行向量的评价函数。

然后,我们分别统计己方、对方的72向量上的长连、成5、活4、冲4、活3、冲3、活2,,,,停停停,后面的就没有了!

最后,我们根据不同的情况,给出不同的得分,例如死棋——对方死棋,那么判断对方是否禁手,如果禁手并且走了禁手那我们胜利了(好像是捡的)……如果我们称5,那我们理所当然的胜利了(当然如果是对方没看见我们偷偷的下上的,也捡到了……但是这种情况是幻觉…………)。当然还有很多情况,我们需要一一评价。总体来说,冲棋部分处理起来代码最多,但是却得到了额外的好处——可以直接生成冲棋点,也就是说不用生成全部招法,而得到非常准确的招法点。

这就是整个评价过程的全貌了。

实际上,评价结果的值只有这么几个:10000、-10000、5000、-5000和一些比较小的数(冲3活2只是根据计数进行了简单评分)。当然,冲3活2的评分过程中,应该考虑先行权分值问题(程序中这个值暂时置0),但是其他的评价里面个人认为不需要。

3、基石——超出边界的alpha-beta剪裁

下一集的程序就可以称为一个真正的五子棋程序了,虽然水平不高,但是毕竟可以走棋了。努力有了回报,总是非常高兴的事情。强烈建议在我更新下一集之前(今天我不会再更新了,至少要等我写完第6个程序——置换表并经过一定量的测试和优化之后,才会发出来。因为冲棋延伸的代码并不让我满意,也许短短的1行并不能解决全部问题。),仔细阅读关于alpha-beta的原理,最好是自己实现这个递归函数,当然看懂也不错。因为这是整个程序最核心的内容之一,虽然这一集也是,代码也很多,但只要耐心看,很容易能弄懂;可alpha-beta剪裁不是那么回事,代码加上注释和空行才不到50行,但是如果不充分理解递归设计方法和运行特性,对后面的空步剪裁、冲棋延伸代码的编写会造成很大的麻烦。建议先自己写一个简单的递归函数,理解一下递归语句前面一直进栈后面一直出栈和单次运行合理即可的设计思想。总而言之一句话,程序能不能真正下起来棋,就看这一哆嗦了!好了,不写了,去看看我的静态搜索应该改几句代码,然后就是构思重构置换表!代码是不写了,累了……

全部文章和源码整理完成,以后更新也会在下面地址:

}

五子棋禁手,指对局中禁止先行一方(黑方)使用的战术,具体包括黑方一子落下时同时形成双活三、双四或长连等三种棋形。禁手只对黑方有效,白方无禁手。黑方禁手的位置称为禁手点。

禁手分为三三禁手、四四禁手、长连禁手:

三三禁手:黑棋一子落下同时形成两个活三,此子必须为两个活三共同的构成子;

四四禁手:黑棋一子落下同时形成两个或两个以上的冲四或活四;

长连禁手:黑棋一子落下形成一个或一个以上的长连。

对黑方的行棋加以限制,从对局的实际棋力的发挥来看,对双方是比较公平的。五子棋是全国智力运动会竞技项目之一,是一种两人对弈的纯策略型棋类游戏。

通常双方分别使用黑白两色的棋子,轮流下在棋盘竖线与横线的交叉点上,先形成五子连线者获胜。在专业五子棋竞赛规则中,另有交换、禁手等规定,用于限制先行方优势。起源于东亚地区,主要流行于华人和汉字文化圈的国家。

棋盘可用木料、硬纸、塑料、布料、石料或环保材料等制成。棋盘由横纵各15条等距离,垂直交叉的平行线构成,在棋盘上,横纵线交叉形成了225个交叉点为对弈时的落子点。邻近两个交叉点的距离要略大于棋子的直径。

}

我要回帖

更多关于 三三禁手黑棋怎么赢 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信