对弈类游戏的人工智能设计(1):评估函数+博弈树算法

前言:

对弈类游戏的智能算法, 网上资料颇多, 大同小异。 我写这篇文章, 并非想做互联网的搬运工。 而是想对当年的经典<<PC游戏编程(人机博弈)>>表达敬意, 另一方面, 也想对自己当年的游戏编程人生做下回顾。

这边我们以黑白棋游戏为例, 从博弈和学习两方面来阐述游戏AI的编写要点。 本文侧重于讲述博弈(评估函数+博弈算法)。
 


博弈:

以前看围棋比赛, 常有人评价棋手水平高: 大局观强(评估局面好), 算路精准(计算步数深, 实战效果好)。 他山之石可以攻玉, 对弈类游戏的AI本质上也是在评估局面, 博弈深度这两点上做足了文章。

(一)评估函数:

让我们先来谈谈局面评估, 那如何从程序的角度去合理评估游戏的局势呢?

首先局面的好坏, 需要综合考虑多个因素(权重不同, 不同阶段重要性的变化), 其次因素影响力需转化为数值来衡量。

为了简化模型, 我们引入评估函数G(s), s为当前的局面, G(s)为当前局面的评估值。
 

  1. G(s) = a1 * f1(s) + a2 * f2(s) + ... + an * fn(s)
复制代码


注: fi(s)为某个评估因素的得分, ai为某个评估因素的权重比

评估函数G(s)的引入, 为游戏AI的智能引入了数学模型, 也是一切的基础。

回到黑白棋游戏本身, 依据经验选定如下特征评估因素:

1)地势估值表

黑白棋和围棋一样, 也遵守着"金角银边烂肚皮"的定律, 四个角的地势值非常大, 其次是四条边。 因此我们再给8*8地图点分配地势值时, 大体满足角边重, 中腹轻的模式。
 

  1. potential_enegy(s) = ∑ pe[x, y] {map[x,y] is occupied, 8>x>=0, 8>y>=0}
复制代码


注: potential_enegy(s) 为地势评估函数, pe[x,y] 为地势估值矩阵, map[x,y]是游戏地图本身。

2)行动力

基于这样的假设: 在某局面中, 选择多, 则灵活主动, 而选择少, 则往往陷入被动。 因此选择多少, 就成为了评估局面好坏的参考因素了。 于是我们把面对某一局面, 可以落子的个数, 称之为行动力。

3)稳定子

所谓稳定子, 是指无论如何, 都不可能被翻覆的子, 最简单的稳定子就是4个角点, 稳定值越多, 获胜的几率就越大。

有了这些评估因素后, 再赋予一定的权重系数, 评估函数就比较完善了。 此时游戏的AI也基本构建完毕, 其棋力能击败初学者, 应该不成问题。

但此时的AI很脆弱, 看似每步都选择最佳落子, 却很容易落入陷阱。 这就是贪心算法, 导致的局部最优陷阱。 如何破这个局呢? 期待王者到来: 博弈树。

(二)博弈树:

博弈树本质就是极大极小的搜索过程,手机游戏账号买号平台相关资料可参考博文: "极大极小博弈树"。

极大极小的算法, 分支繁多而冗余, 于是引入alpha+beta剪枝做优化, 它可以快速裁剪不必要的搜索分支, 提高搜索效率。

关于这块, 就不再具体展开, 参见如下博文: A*算法/博弈树, 机器博弈中的基本搜索算法;

alpha+beta剪枝的极大极小过程示意图:


负极大值算法伪码:
 

  1. // 负极大值算法
  2. int negamax(GameState S, int depth, int alpha, int beta) {
  3.     // 游戏是否结束 || 探索的递归深度是否到边界
  4.     if ( gameover(S) || depth == 0 ) {
  5.         return evaluation(S);
  6.     }
  7.     // 遍历每一个候选步
  8.     foreach ( move in candidate list ) {
  9.         S' = makemove(S);
  10.         value = -negamax(S', depth - 1, -beta, -alpha);
  11.         unmakemove(S')
  12.         if ( value > alpha ) {
  13.             // alpha + beta剪枝点
  14.             if ( value >= beta ) {
  15.                 return beta;
  16.             }
  17.             alpha = value;
  18.         }
  19.     }
  20.     return alpha;
  21. }
复制代码


展望:

有了评估函数和博弈树后, 其游戏AI有了飞跃的进步, 但一山更有一山高, 我们是否能够更进一步呢?

对于评估函数, 我们当前的策略是基于经验, 选择评估因素和权重分配。 能否用机器学习的方法,自动实现因素(特征)选择, 权重系数合理分配呢?

而对于博弈算法本身, 是否还有优化的地方? 搜索深度和搜索分支的广度如何权衡?

最重要的如何设置进阶的AI难度, 增强用户的体验?

因篇幅受限, 决定放到下一篇博文中。

总结:

为何选择黑白棋作为对弈类游戏AI解说的对象, 一方面游戏规则简单, 另一方面其评估模型容易构建, 且其搜索分支少+搜索深度深, 这些对快速实现并理解博弈游戏的AI核心算法有非常大的帮助。 该博文主要讲述了评估函数和博弈树的原理和优化。 下文讲着重讲述下 博弈游戏的AI如何学习, 以及性能优化的进阶篇。

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
•Alpha-Beta剪枝(Alpha-Beta pruning) 对于一般的最大最小搜索,即使每一步只有很少的下法,搜索的位置也会增长非常快;在大多数的中局形中,每步平均有十个位置可以下,于是假设搜索九步(程序术语称为搜索深度为九),就要搜索十亿个位置(十的九次方),极大地限制了电脑的力。于是采用了一个方法,叫“alpha-beta剪枝”,它大为减少了检测的数目,提高电脑搜索的速度。各种各样的这种算法用于所有的强力Othello程序。(同样用于其他游戏,如国际象和跳)。为了搜索九步,一个好的程序只用搜索十万到一百万个位置,而不是没用前的十亿次。 •估值 这是一个程序中最重要的部分,如果这个模块太弱,则就算算法再好也没有用。我将要叙述三种不同的估值函数范例。我相信,大多数的Othello程序都可以归结于此。 格表:这种算法的意思是,不同的格有不同的值,角的值大而角旁边的格子值要小。忽视对称的话,盘上有10个不同的位置,每个格子根据三种可能性赋值:黑、白和空。更有经验的逼近是在游戏的不同阶段对格子赋予不同的值。例如,角在开局阶段和中局开始阶段比终局阶段更重要。采用这种算法的程序总是很弱(我这样认为),但另一方面,它很容易实现,于是许多程序开始采用这种逼近。 基于行动力的估值:这种更久远的接近有很强的全局观,而不像格表那样局部化。观察表明,许多人玩者努力获得最大的行动力(可下的数目)和潜在行动力(临近对手子的空格,见技巧篇)。如果代码有效率的话,可以很快发现,它们提高力很多。 基于模版的估值 :正如上面提及的,许多中等力量的程序经常合并一些边角判断的知识,最大行动力和潜在行动力是全局特性,但是他们可以被切割成局部配置,再加在一起。子最少化也是如此。这导致了以下的概括:在估值函数中仅用局部配置(模版),这通常用单独计算每一行、一列、斜边和角落判断,再加在一起来实现。 估值合并:一般程序的估值基于许多的参数,如行动力、潜在行动力、余裕手、边角判断、稳定子。但是怎么样将他们合并起来得到一个估值呢?一般采用线性合并。设a1,a2,a3,a4为参数,则估值s:=n1*a1+n2*a2+n3*a3+n4*a4。其中n1,n2,n3,n4为常数,术语叫“权重”(weight),它决定了参数的重要性,它们取决于统计值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值