人工智能---Alpha-Beta剪枝(中国象棋)

摘要:本次实验我们基于Alpha-Beta剪枝算法设计了一个中国象棋博弈程序, 并综合考虑了棋力,攻击能力,保护能力多种因素设计了棋局的静态评估函数。通过实验结果反映出该静态评估函数的设计能够比较好地引导程序进行攻击和防守,在深度为2的搜索树上取得了比较好的效果。

导言

  • 尽管目前五子棋,国际象棋,围棋等博弈程序已经取得了较大成功,但是中国象棋由于起步晚,复杂度高,仍然有许多技术难题未被解决。本次实验我们在Alpha-Beta剪枝算法的基础上,根据平时下象棋时的思考过程(知识)来设计棋局的静态估计函数。
  • Alpha-Beta剪枝是一种搜索算法,用以减少极小化极大算法搜索树的节点数。这是一种对抗性搜索算法,主要应用于机器游玩的二人游戏(如井字棋,象棋,围棋)。当算法评估出某策略的后续走法比之前策略的还差时,就会停止计算该策略的后续发展。该算法和极小化极大算法所得结论相同,但剪去了不影响最终决定的分枝。

实验过程

  1. 基本设计:
    本次实验使用python3的Qt5模块实现图形界面以及实现象棋的基本操作。所有源代码在/src/chess.py中。Chess.py包含了一个继承了QMainWindow的chess类,chess类中使用一个字符串矩阵(即代码中的全局变量board)来表示棋盘。此外chess类主要还实现了以下几个函数:
    gen_moves: 从当前棋局开始生成所有可能的下一步
    evaluate:棋局的静态评估函数
    make_a_move: 在当前棋局下一步棋并更新board,但不需更新界面
    move_back: 退回上一步棋并更新board,但不需更新界面,用于搜索时的回溯,节省存储空间
    AlphaBeta:通过AlphA-Beta剪枝算法搜索出比较好的走法

  2. 核心设计
    本次实验的核心设计Alpha-Beta剪枝的实现以及棋局的静态估计函数。以下分别对这两个函数的设计思想进行详细说明。
    Alpha-Beta剪枝算法的流程如下:
    在这里插入图片描述

以上是通用的算法实现框架,在这个实验中,我们使用-1000000和1000000来代替负无穷和正无穷,使用board来表示当前节点,并在递归过程中记录目前已找到的较优解。

棋局的静态评估函数:

  • 我们所设计的评估函数的基本思想是棋力相加和攻击力,保护力对比,目标是引导程序往增加对对方的威胁力以及削弱对方的棋力的方向去下棋,从而实现基本的攻守能力。
  • 棋力:我们给每个棋子定义了一个棋力值(大分玩家的棋子的棋力值大于0(黑方),小分玩家的小于0(红方)),将当前棋局的所有棋子的棋力相加即可得到评估双方棋力的差距。若差距大于0,则说明大分玩家(黑方)比较有利,若小于0,则说明小分玩家(红方)比较有利。等于0则双方棋力相对均衡。
  • 攻击能力:此外,棋子的相对位置(攻击能力)也是评估棋局好坏的一个重要的因素。我们将一个棋子的攻击能力定义为它在当前所在位置所能攻击到的所有棋子的棋力之和。一个棋子在当前能够攻击到棋子越多,越重要,那么该棋子的攻击能力就越强。攻击能力大于0表示大分玩家对对方的攻击能力,攻击能力小于0表示小分玩家对对方的攻击能力。我们将棋局中所有棋子的攻击能力相加即可得到双方攻击能力的差距。差距大于0则说明大分玩家处于有利局势,小于0则小分玩家处于有利局势,等于0则相对均衡。
  • 优先权及保护能力:再进一步考虑实际情况,攻击力的计算还要考虑当前棋局轮到哪一方下棋,以及我们还可以考虑棋子对己方棋子的保护作用。若当前棋局不是轮到这一方的棋子下棋,那么我们给这一方的棋子的攻击力乘以一个小于1
  • 的正系数(0.1)来简单区分先攻击和后攻击的差距。对于保护作用,一个棋子的保护作用定义为该棋子攻击范围内己方棋子的棋力之和。保护作用大于0表示对大分玩家有利,小于0则表示对小分玩家有利。
  • 随机扰动:在运行程序的过程中,发现相邻两个棋局的评估值有不少是相等的,主要是因为其攻击力和棋力是一样的,这种情况下程序往往会浪费掉不少可能比较好的走步。为了让程序在这种情况下有更多的可能性选出比较好的走法,我们在原有的评估函数的基础上加上一点小的随机扰动来帮助程序选出好一些的走法。我们以棋子的位置坐标乘上一个小的随机整数来作为扰动值,且该扰动值不会超过一个棋子的棋力值,以此来确保产生的扰动不会太大以致干扰了对棋力的评估。
  • 综上,我们的静态评估函数=每个棋子的棋力之和 + 每个棋子的攻击力之和 + 每个棋子的保护力之和 + 随机扰动值
  • 棋子的攻击力 + 保护力的计算由代码中的attack_ability函数实现,详见代码。
    对于各个棋子的棋力值设置如下:
棋子 帅/将
棋力值 100 450 900 400 200 200 100000

结果分析

通过与程序下象棋博弈对程序棋力的评估如下:

  • 性能
    实验中设置搜索深度为2,程序响应时间较好,大致在0.5秒内,棋子数越少响应速度越快。程序每次下棋需要搜索的节点个数绝大部分在2000个以下,一开始的搜索次数大部分集中在1200-500之间,到后面棋子数比较少的时候搜索的节点数在500以下。

  • 程序的棋力:
    程序能够主动发动攻击和防守,每次至少能够对战几十回合,愚蠢行为很少(例如白白送上棋子被吃),总体棋力接近正常人,但还比较难以赢过人类玩家。主要是因为搜索深度只有2层,程序难以设计多个连续走步来威胁对方的将,即程序的攻击和防守策略比较简单。限于算法的性能,难以将搜索深度提升到4层(每步棋所需的时间约一分钟,每次搜索大约20万个节点)。

  • 总体评价:
    该算法的静态估计函数设计相对比较好,综合考虑了几个重要的因素,并且程序的行为也一定程度反映了该评估函数能够比较好的引导程序进行攻击和防守,特别是在将军的防守上几乎没有什么失误。但该程序的一大局限之处在于性能上不够好,无法在短时间内搜索4层。通过对代码的优化(例如尽量减少矩阵或列表的拷贝,减小算法复杂度等),算法性能提高了几倍,但仍然远远不够,可能是比较大受限于python解释器的性能。因此,若用C++来实现将有比较大的可能大大提高算法性能。

结论

这次实验中我们充分体验到了静态估计函数在Alpha-Beta剪枝算法效果的重要性。实验过程中静态估计函数的设计也经过了多次的修改,从最简单的棋力相加,再到估计能力和保护能力的考虑,再到最后随机扰动的设计,该过程中程序的棋力提升非常明显,并且程序的一些较愚蠢的行为也是我们改进静态估计函数的重要参考。另外,静态函数的设计也会大大影响剪枝的效果。若静态函数的函数值过于集中,则有可能使得剪枝的概率变得太小,大大增加了所需搜索节点的个数。所以静态估计函数也应该要能够尽量好的区分相近棋局的好坏。

代码

链接:中国象棋

主要参考文献

  1. 维基百科,https://zh.wikipedia.org/wiki/Alpha-beta剪枝

  2. 陈镜超:中国象棋搜索算法的改进

  3. 基于博弈树搜索算法的中国象棋游戏的设计与实现,期刊《自动化与仪器仪表》第十期,P96-98

  4. 源代码参考:https://github.com/RohanWong/Chinese_Chess_AI

猜你喜欢

转载自blog.csdn.net/qq_36347365/article/details/87011194