前段时间柯洁对战 AlphaGo 的新闻比较火,最终柯洁毫无悬念的以 0:3 告负。人工智能又下一城,离科幻电影中那样统治地球又近了一步。当然,也许我完全是多虑了,毕竟愚蠢且爱作死的人类有无数种方式作死自己,像什么无休止的破坏环境使地球不宜居住啦,无止境的贪婪引发战争引爆核武库啦,无克制的探索宇宙引来外星人占领地球啦等等,反正不差人工智能这一个。

  好了,最近脑洞有点大,还是言归正传吧。接下来要说的不是 AlphaGo 如何厉害赢了柯洁。毕竟以我的智商,围棋都学不会,更别说熟悉人工智能在围棋方面的应用了。但比围棋简单得多的五子棋我还是会下的。虽然技术弱到爆,以至于没人愿意和我下。于是只能自己实现一个,和电脑对练了。下面就介绍一下五子棋的实现原理。

  五子棋有黑、白双方,假设我们是白方,电脑是黑方,我们和电脑交替落子。我们落子时自然会有我们的逻辑去计算考虑到最优位置,但电脑如何知道每一步该落在哪里呢?这就需要计算落子在棋盘中各个点的优劣了。为了方便比较,我们给每个点打分,每一步黑子都将会落子在分数最高的一个点上。接下来只需要考虑打分的策略了。可以想到的打分策略有如下几点(下文中提到的“我方”,是站在电脑即黑子方的角度的,所以代表的是黑子):

  • 下棋过程中有两个方面需要考虑:尽可能的让更多的我方棋子连续的出现在一条线上;尽可能的阻止更多的对方棋子连续的出现在一条线上。所以计算某一个点的分数时,如果落在那个点能使我方出现更多的连续的点,则分数增加;如果能阻止对方出现更多的连续的点,则分数也增加。

  • 计算落点的分值时,应该考虑到落点对当前棋局所有可能的影响。一个落点应该会在 8 个方向上影响当前的棋局。但由于每两个对应的方向可以看成是一个方向的左右延伸,所以可以简化为 4 个方向来计算。当前落子点的分数即为 4 个方向上分数的总和,如下图所示:

Chrome Suggest

  • 为进一步简化模型,我们选取其中一个方向来讨论。一条直线上出现连续 5 个同色的棋子才会取得胜利,所以需要以连续的 5 个棋格为一组来作为计分的原子单位。一个落子点在一条直线上最远可向左和向右分别影响 4 个棋格,在这个区间内会有 5 种不同的组合方式。所以当前落子点在当前方向上的分数即为这 5 个组的分数总和。如下图所示:

Chrome Suggest

  • 接下来计算一个组的分数。有两种情况需要考虑:当前组内已出现了不同颜色的棋子,当前组内还未出现不同颜色的棋子。前一种情况下,落子在当前组内,就这一组而言,不可能产生五子相连的获胜场景,对当前棋局不会产生任何影响,所以可以计 0 分。后一种情况会产生有效得分。

  • 当前组内已有的同色棋子个数不同时,当前组的得分应该是不同的。如考虑下面的场景:某一组内已有 3 个同色棋子,而另一个组内有 4 个同色棋子,显然当前落子时应该落在 4 个棋子的组,这样就可以直接获得胜利了。同理,其它个数的棋子时,也是落在同色棋子数更多的组内,获胜的几率更大。所以有更多的同色棋子的组应该获得更多的分数。

Chrome Suggest

  • 上面说到组内同色棋子越多,分数越大。但当组内棋子递增一个时,分数应该递增多少呢?可以看下图所示的场景:当落子在左图中的中心位置时,可以使 8 个组都拥有 3 个同色的棋子;当落子在右图中的紧挨 3 个棋子的左侧或右侧时,可以使一个组出现 4 个同色的棋子。明显落子在右图会使胜利更近一步。可见,即使是 8 组同样数目的棋子,也不应该比一组多一个数目的棋子得分多。所以只要用大于八进制的计分方式即可。

Chrome Suggest

  • 为简化操作,采用十进制记分。计分方式如下:

    当前组内仅有一个同色棋子时,记 1 分
    当前组内仅有两个同色棋子时,记 10 分
    当前组内仅有三个同色棋子时,记 100 分
    当前组内仅有四个同色棋子时,记 1000 分
    当前组内仅有五个同色棋子时,记 10000 分

  • 上面定义了计分方式,但未考虑到另一种情况:假设两个不同的组内分别有对弈双方的相同数目的棋子。按上述计分规则,两组获得的分数应该是相同的,则当前落子时,只能随机选择两组中的一个了。显然,落在我方棋子所在组内能够直接获得胜利。所以当不同组内双方棋子数相同时,我方棋子所在组应该获得更多的分数。为满足此条件,只需在当前计分规则的基础上加 1 即可。

Chrome Suggest

  • 所以,现在的计分规则应该如下:

    当前组内仅有一个对方同色棋子时,记 1 分;仅有一个我方同色棋子时,记 2 分
    当前组内仅有两个对方同色棋子时,记 10 分;仅有两个我方同色棋子时,记 11 分
    当前组内仅有三个对方同色棋子时,记 100 分;仅有三个我方同色棋子时,记 101 分
    当前组内仅有四个对方同色棋子时,记 1000 分;仅有四个我方同色棋子时,记 1001 分
    当前组内仅有五个对方同色棋子时,记 10000 分;仅有五个我方同色棋子时,记 10001 分

上述计分规则定义好了,接下来只需编码实现即可,就不细说了。具体代码见 GitHub。同时上面也有一个 demo 五子棋