共计 1779 个字符,预计需要花费 5 分钟才能阅读完成。
nodejs 版,麻将智能机器人出牌算法。
简述
麻将,起源于中国,粤港澳及闽南地区俗称麻雀,
由中国古人发明的博弈游戏,娱乐用具,一般用竹子、骨头或塑料制成的小长方块,上面刻有花纹或字样,
北方麻将每副 136 张,南方麻将多八个花牌,分别是春夏秋冬,梅竹兰菊,共计 144 张。
项目
请加星收藏仓库地址,方便以后学习使用。
github 地址
使用方法
# 下载
git clone https://github.com/wallace5303/nodejs-game.git
# 进入文件
cd nodejs-game/aiTable
# 安装
npm install
# 运行
node demo.js
demo 内容
# 麻将牌所有对应的数字 id,请查看配置文件:cardConfig.json
const outCardLogic = require('./outCardLogic');
// 手牌 1 万,2 万,3 万,8 万,8 万,1 条,5 条
const cards = ['31' , '32', '33', '38', '38', '41', '45'];
// 选出一张最优牌
var outLogic = new outCardLogic();
// 第二个参数为万能牌,可选。var card = outLogic.outAI(cards);
console.log("选出的最优牌是:%j", card); // 41(1 条)
分类
字牌(合计 28 张)
- 风牌:东、南、西、北,各 4 张,共 16 张。
- 箭牌:中、发、白,各 4 张,共 12 张。
花牌(合计 8 张)
- 春、夏、秋、冬,梅、兰、竹、菊,各一张,共 8 张。
- 注:这种牌很少种类的麻将会用到。
序数牌(合计 108 张)
- 万子牌:从一万至九万,各 4 张,共 36 张。
- 筒子牌:从一筒至九筒,各 4 张,共 36 张。也有的地方称为饼,从一饼到九饼。
- 索子牌:从一索至九索,各 4 张,共 36 张。也有的地方称为条,从一条到九条。
相关术语
麻将应对的五种标准状态,是“吃”、“碰”、“杠”、“听”、“胡”。在正式比赛中,五种状态的官方语言都是汉语,包括国际比赛。
- 吃: 上家打出牌,与下家的牌正好组成一副顺子,他就可以吃。
- 碰: 其他人打出一张牌,自己手中有两张相同的牌正好组成一副刻子,他就可以碰。
- 杠: 其他人打出一张牌,自己手中有三张相同的牌,即可杠牌,称为明杠,倒下这个杠,再到排尾抓一张牌,将手中不需要的一张牌打出。手中有三张相同的牌,又抓到一张相同的牌,称为暗杠,扣下,别人不知道是啥牌,再到排尾抓一张牌,将手中不需要的一张牌打出。“明杠”比“吃”优先,如果你要杠的牌刚好是出牌方下家要吃的牌,则吃牌失败,杠牌成功。
- 听: 当你将你手中的牌都凑成了有用的牌,只需再加上最后一张便可和牌,你就可以进入听牌的阶段,报听后不能吃、碰、杠,且只能打出本轮摸到的牌。
- 和:(读音:hú,ㄏㄨ)当最终牌型满足 m AAA+nABC+DD(m、n 可以为 0),即可和牌(少数特殊牌型除外)。四位玩家谁先和牌谁为胜利,得分由底分乘上番数。具体视比赛详细规则而定。
牌型术语
- 连子:一万二万三万
- 刻子:一筒一筒一筒
- 将:一条一条
胡牌公式
- N×连子 + M×刻子 + 1×将
- N>=0, M>=0
鬼牌
鬼牌的定义就是能够变成任意牌的牌,也叫万能牌。
案例分析
举个栗子,看看真实的人是怎么思考出牌的:
- 1 万 2 万 3 万 5 条,打 5 条
- 1 万 2 万 3 万 1 条 1 条 6 条,打 6 条
解决思路
从上面的例子可以看出来,打牌的过程,其实就是打完之后的牌面,胡牌概率最高。
所以,算法变成了评估牌面积分的算法,越高说明牌越好,也说明这副牌可以胡的概率更高。
评估方法
为了评价这副牌的积分,也就是胡牌的概率,我们可以给他再摸 N 张牌,看看胡牌情况。
参考如下示例,可以很直观得出牌面积分:1 筒 2 筒 3 筒 > 1 筒 2 筒 3 筒 2 条 3 条 > 1 筒 2 筒 3 筒 2 条。
- 1 筒 2 筒 3 筒
已经胡了,胡牌概率为 1
- 1 筒 2 筒 3 筒 2 条
只摸 1 张牌,那么只有当摸 2 条的时候,才会赢,胡牌概率为 1 /9* 摸条的概率,有将。
- 1 筒 2 筒 3 筒 2 条 3 条
只摸 1 张牌,那么只有当摸 1 条 4 条的时候,才会赢,胡牌概率为 2 /9* 摸条的概率,无将。
表格生成
有了评估方法后,我们只需要对每个花色的手牌,分配 N 张牌给他,然后计算胡牌概率,就可以知道牌面积分。
不过考虑到计算量太大,所以我们可使用查表法,提前计算好,方便快速查找。
出牌算法
- 遍历手上的非鬼牌,计算排除掉这张牌后的牌面积分最大值,这张牌就是要打的牌。
- 如果打出能听牌了,就取一个听牌最多的牌打出去。
正文完
发表至: javascript
2019-08-16