Posts AI五子棋实现
Post
Cancel

AI五子棋实现

可以实现一个你下不赢的五子棋吗?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
win = [
  [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
]

myScore = [
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
]

aiGobangScore = [
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
]

人工智障五指棋

自己做的 AI 五子棋,能下得赢它吗?

五子棋的实现原理

01.png

实现的原理很简单,就是一个二维数组。看起来就像上图这样,横向15个0,纵向15个0。0代表着棋盘的这个位置还没被人下过,这时候用1来标记电脑,2来标记玩家。五子棋背后的动作就是去改变这225个格子,0变成1或者2。

程序需要做的就是在每次下完之后做个判断,如果当前改变的位置的四个方向 \/|一 ,有5个相同的数字,就赢了。

02.png

如上图所示,人工智障机器人只会一种走法,从(0, 0)点开始一直往右走,狡猾的人类看出了机器人的这个弱点,默默的在中间连下5个子,获取了胜利。

给机器人加点戏

加戏1:机器人知道了所有的赢法

1.所有横向的赢法 03.png 红色的框框每次向右挪一步框住5个格子,一行可以框11次,一共15行,就是165种可能性,代码大概就长这样子 04.png

2.所有纵向的赢法 05.png 先框住第一列的5个,一列可以框11次,一共有15列,也是165种可能性。

3.所有 \ 方向的赢法 06.png 框框可以往右挪11下,往下挪11下,所以一共是 11 * 11 = 121 种赢法。

4.所有 / 方向的赢法 07.png 框框同样可以往右挪11下,往下挪11下,一共是 11 * 11 = 121 种赢法。

这个时候机器人已经知道了一共有 572 种赢法了,靠感觉下棋的人类颤抖吧。

初始化两个赢法数组,先全部置零,后面会在每种赢法上做文章 08.png

加戏2:上帝视角,知道他能怎么赢,也能知道你能怎么赢

初始化两个分数数组 09.png 这个我们又见到了这个 15 * 15 的格子了,但这次是两个,一个是玩家的,一个是 AI 的,分别用来统计在每个点下棋的分数,对这里用分数这个词,哪个点分数高就往哪个点下。可是为什么有两个呢,因为一方面 AI 想要获胜,另一方面还要阻止愚蠢的人类获胜,所以需要找到最有价值的那个点,也就是算法里面分数最高的那个点,因此需要进行如下的事情。

1、 (u, v) = (0, 0) ,设定预下子的位置。max 用来统计分数最高的一个点

2、找出所有 225 个点所有为 0 的点,也就是可以下的点,再对每个可以下的点再进行分析所有 572 种赢法。但是不是只要能下的点,对这 572 种赢法都有意义呢?其实不是的,还记不记得一开始那四张图,来表示这 572 种赢法是怎么来的。 10.png 当时涉及到一个赢法统计方案,就是把这四张图出现的所有赢法放在了一个三维数组里面。 11.png 这个有什么用呢?其实就是让机器人聪明一点,不能赢的路就别走了,别浪费电去整些没用的。

3.回到赢法这个问题上来,我们之前整过了一个赢法数组还记得不。 08.png

我们每下一步棋,除了在页面上涂个小白点小黑点,其实背后是有个状态记录器的,电脑不是人,不会看这些小点点。所以每下一步棋,就会去看看所有的赢法,在里面找出可能的赢法,然后在玩家的赢法数组相应的赢法位置加1。举个例子。 10.png

又见到这个图了,假如玩家在左上角下了一个字,他这步棋可能存在几种赢法呢?对,就是三种

1
const myWin = [1, 0, 0, '...' , 1, 0, 0, '...', 1, '...', 0] // 长度 572

通过肉眼,我们看出来了,一共有 3 种赢法,分别是上面的前三张图。他们分别在这 572 长度的数组的什么位置呢?我们之前已经算过,第一张图有 165 种赢法,第二张图也是 165,第三张图 121,第四张图 121。那这三个位置就是在第 1 位,第 166 位和第 331 位。

怎么才能算赢呢?如下图所示,这里框出第一种和第二种的赢法。 12.png 我下第二个子的时候,它可以通过第一种赢法赢,也可以通过第二种赢法赢,当然还不止这两个,还有竖的和斜的赢法,其他先不管了,这时候我是不是要在 myWin 的第一种和第二种赢法上各加个+1s,最后 myWin 变成了这个样子

1
const myWin = [2, 1, 0, ...] // ... 里面也是有一些 1 的

如果这个数组凑到了 5,就证明我赢了,如果 AI 堵住了你第一种赢法的去路,那你就不可能在第一种赢法上获胜咯。这里有个注意的点,你下了第一步之后,AI 还有没有可能通过第 1 种胜利方法获胜?是已经不可能了。 13.png AI 不只不能在第一种赢法上获胜,也不能在第 166 种赢法中获胜,也不能在第 331 种赢法上获胜。所以要给 AI赢法方案上的这些位置设置个 -1 值,一步棋毁灭了 AI 的 3 条获胜道路。

1
const aiWin = [-1, 0, 0, ..., -1, ..., -1, ..., 0]

4.确定最该下的那个点,还记得之前弄过一个记分板吧,玩家和 AI 各有一个。 09.png

先看看玩家和 AI 有意义的点。 14.png 上图是针对 225 个点中为 0 的点,也就是没有被下过的点,进行所有不费电的赢法比对。对两个棋盘的每个位置进行打分,这里一个点上的分数和,是会累加所有赢法的。最后就会得到两个棋盘的分数。那么怎么进行判断呢? 15.png 这里用 u, v 来存储要下的位置,如果啊,这个点的分数比最大的分数高,那最大的分数就变成这个点的分数,u, v 就姑且相信当前的 i, j 点是最好的。如果相等的话呢,就也不用把 myScore[i][j] 的分数赋给最大值 max 了,因为都一样,如果这个点对于 AI 分数来说,比他之前姑且相信的那个值要大,那就继续姑且相信 u, v 最好的位置就是 i, j 咯。下面同样的逻辑再走一遍 ai 的分数盘,全部走完之后 u, v 看透了全局,找到了一个最好的位置,最后就下在那个位置上吧。

最后纵观全场,AI 找到了个分数最高的地方落脚。落完脚之后,执行一个跟人类一样的判断。 16.png 下完之后看看所有的赢法,在不费电的点上,加个1,同时在人类的赢法统计表上的这个赢法上标记个 -1,这种赢法人类已经不能取得胜利了。如果刚好,这个点已经被加到5了,也就是,AI 获胜了。

结论

所以说啊,算计是算计不过 AI 的,要想胜利,还是拔电源吧。

This post is licensed under CC BY 4.0 by the author.
Trending Tags
Contents

Trending Tags