网上斗地主记牌技巧 如何写一个斗地主的AI?
提前声明一下,我只是一个编程新手,水平不高。
毕竟是一年前的问题了,也许我现在的水平已经远远比不上题主。
首先我们需要明确斗地主这种牌类游戏与其他AI的区别,如棋类游戏,以选取针对性的算法。
棋类游戏的局面对玩家是公开的。
因此我们可以用基于决策树的算法,如alpha-beta剪枝对之后的很多步进行模拟,找到最优解。
而斗地主这种牌类游戏,由于我们得到的信息相当有限(只有自己的手牌与对手打出的牌),很难搜索很多步,基本还是靠“专家系统”-以人类思维进行模拟,将人类智慧中的一些术语转换为计算机能听懂的语言。
前不久刚刚写了一个斗地主AI。
我认为关键在于拆牌和估值。
我们认为“牌”是0-53的数字序号。
其实也可以无视花色,将其视为0-14(0代表3,14代表大王)的数字序号,允许重复。
先实现数据结构。
需要定义一个类:牌组(不妨叫CardCombo),给出一堆牌的输入,这个类需要确定牌组的类型(如对子,三条,飞机,顺子等等),大小(如对6>对4)。
判定牌组类型考虑牌组中同点数牌的数量。
比如牌组中同点数牌数量为1(3-大王,任何点数仅有1张),可能是单张或者顺子。
同点数牌数量2-对子,双顺。
3-三条,飞机。
3+1-三带1,飞机+小翼。
这需要自己慢慢分类讨论。
接下来是出牌。
斗地主出牌有两种:一种己方是先手,无限制的出牌(认为是攻击型的),另一种是跟牌(认为是防守型的)。
出牌的合法输出仅取决于自己手牌(出自己有的牌),而跟牌需要:出自己有的牌,牌类型与所跟牌:类型相同,张数相同,等级较高。
实现了这一点之后,您可以设计出有牌就跟的AI,合法性是可以保证的,但是这样的AI战斗力不高。
想提升AI战斗力,您或许需要实现拆牌的功能,即将手牌拆分成比较好的组合。
这里的“好”,粗略指的是手数尽可能少,但尽量用对牌组的估值进行判断。
比如手牌是33345677,我认为常人思路应该是拆成(34567)(33)(7)。
这里提供一个简单思路(我的思路加入了大量特判,之后举例优化。
)拆牌顺序:炸弹-三条-双顺-顺子-对子-单张。
例如0JQQK。
拆分结果应如(333)(445566)(7)(888)(910JQK)。
这比有牌就跟的AI相比就要好很多。
优化很多,比如发现破坏对子数量过多不拆顺子,将双顺拆成两个顺子(3445566778拆成34567与45678)等。
对于一个可以当做一手牌打出的CardCombo,我们可以对它进行估值。
整手牌的估值就是这些拆分好的牌组与牌组数量(出完牌需要的轮数,越小越好)的线性组合。
这里粗略说一下估值的思路,大牌肯定要设计成高权值。
特殊类型的牌权值也应该有增益。
如33一般是优于单张3的。
接下来是进攻性的主动出牌了。
一般自己有好的牌型(如双顺,飞机,顺子)对手难以管上,可以优先出,占据主动权。
更强的AI要考虑队友与对手可能没有的牌型,针对弱点进行进攻,或避免卡队友。
防守型的被动出牌其实不一定要出拆好的Combo中的牌,因为给了跟牌的限制,搜索数量并不多。
这里可以假设出某个Combo,估计剩下手牌的价值,如果破坏牌组并不严重,就可以出这个Combo.
再优化就是残局搜索了。
比如,自己剩下两手牌,有一手是绝对大牌。
比如双王已经出过,你手里一张2一张7,先出2先出7?答案是先出2.这种局面想优化需要好好考虑。
这个框架是基于人类经验的。
其实需要考虑的事情很多,再提升性能也很困难。
现在BP神经网络比较流行,思路是将(我方有的手牌,上家出的牌,已经出过的牌)作为完全描述已知信息的游戏状态state,作为神经网络的输入,计算出我方选择所有合法动作(action,也就是可行的操作-出符合游戏规则的牌或跳过)的概率。
但是凭我目前的水平很难实现。
也许之后实现神经网络会更新答案。