Skip to the content.

简述

打麻将,需要运气,也需要脑力。作为玩家,需要搭好牌架子,然后一张一张的摸牌,最后达到听牌,最终胡牌。
本文讲述的即是AI如何尽量做到高智商的打麻将。其中摸牌我们是控制不了的,所以就在打牌上下手。
首先还是先复习下麻将玩法。
github地址

使用

maven

<dependency>
    <groupId>com.github.esrrhs</groupId>
    <artifactId>majiang_algorithm</artifactId>
    <version>1.0.15</version>
</dependency>
// load
AITableJian.load(Files.readAllLines(xxx));
AITableFeng.load(Files.readAllLines(xxx));
AITable.load(Files.readAllLines(xxx));
// 出牌
int card = AIUtil.outAI(cards, gui);
// 碰
boolean isPeng = AIUtil.pengAI(cards, gui, pengCard, 0.d);
// 杠
boolean isGang = AIUtil.gangAI(cards, gui, gangCard, 0.d);

花色分类

牌型术语

胡牌公式

鬼牌

鬼牌的定义就是能够变成任意牌的牌,通常是提前指定或者每次随机决定,比如白板做鬼,如下图:
image
在本文中,不需要考虑鬼牌,因为不会打鬼牌,所以我们只需要把其他牌做的完美,就可以随便和鬼牌达到听牌胡牌。

案例分析

我们先举几个直观的例子,看看人是怎么思考出牌的

解决思路

从上面的例子可以看出来,打牌的过程,其实就是评估打完之后的牌面,取一个最佳牌面。
也就是说,算法变成了评估牌面积分的算法,越高说明牌越好,也说明这副牌可以胡的概率更高。

评估方法

为了评价这副牌的积分,也就是胡牌的概率,我们可以给他再摸N张牌,看看胡牌情况。参考如下示例,可以很直观得出牌面积分:1万2万3万 > 1万2万3万2条3条 > 1万2万3万2条。

表格生成

有了评估方法后,我们只需要对每个花色的手牌,分配N张牌给他,然后计算胜率,就可以知道牌面积分。
不过考虑到计算量太大,所以我们可依然使用查表法,提前计算好,方便快速查找。
当然,这里的问题就是不会去参考当前桌子剩余的牌,不过相比计算效率,这一点牺牲是可以接受的。

牌型编码

查表的第一步,要对手牌进行编码做key。

表生成

在生成表的阶段,时间是不值钱的,所以生成方法我们可以任意穷举。

评估算法

有了前面辛苦生成的表格,那么评估积分算法就很简单了。

出牌算法