大概花了一下午,C++ 期末作业做了个简单的 AI 五子棋,使用 minimax 算法和 alpha-beta 剪枝。
记录一下如何实现:
-
需要有评估函数,评估下一步棋的好坏。
取棋盘上所有的连续的五子组合,除去五个空的情况,然后从黑白两方,分别通过连成了哪些模式,累加双方得分,最后用黑方得分减去白方得分,作为当前棋盘的评估值。 -
选择落子位置时,只考虑当前棋盘上有棋子的格子周围一定范围内的空格,避免搜索过多无意义的位置。
-
实现 minimax 算法,递归地模拟双方落子,直到达到设定的搜索深度。
双方都假定对方会在己方落子后,会选择对己方最不利的落子。因此己方需要选择对方无论如何落子,都会使己方评估值的最小值最大的落子,以保证己方利益能够最大化。我要得分最高,对方要让我得分最低,那么对方让我得分低,但比其他低的相对最高的,就是我得分最高的选择
-
使用 alpha-beta 剪枝,减少不必要的搜索。
在递归搜索过程中,维护两个值 alpha 和 beta,分别表示当前己方能够获得的最小评估值和对方能够获得的最大评估值。己方遍历所有空位,然后对方也根据己方落子,评估剩余空位。如果在评估前 n 个落子时,得出己方最小得到的评估值为 ,那么在评估后续己方落子时,对方不断尝试剩余空位,尝试找到最小的下法,使得 尽可能小。
如果对方发现可以有某个落子,得到 的评估值,那么对方肯定会选择这个落子而不是其他落子,使得己方获得更低的评估值,己方肯定也不会选择这个己方落子,所以后续该己方落子所对应的对方落子就不需要再继续评估了,达到剪枝的目的。
我下 A / B,对面接下来可以下 C/D / 和 E/F, 如果下 A 我最低可以拿到 10 -> alpha,而下 B 之后对方下 E 的话我只能拿到 1 -> beta,那么 beta < alpha,对方肯定下 E,既然我知道下 B 对方必下 E,则我也不会下 B 而会下 A,那么没人在乎 F 是多少,反正下 B 必下 E,所以不用计算 F 的评估值。
反之如果遍历完 E 和 F 以及后续剩下的,都没有让 beta < alpha 的情况,那么说明下 B 比下 A 更好,我就会选择下 B。
评估规则很简单,只是单纯检测了连子,有空再优化吧,应该把五子的视野扩到到六子?
1 | int pattern_score(int pattern[5], int player) |
代码见 z0z0r4/gobang
这里放一次对局的记录
1 | Gobang Game Initializing! |