最近在使用Cocos Creator做一款四人斗地主的手机游戏,半成品(仅前端)代码附在最后,仅供参考。游戏中的单机(人机)模式以及游戏过程中的托管都需要出牌算法的设计,因此借这篇博客梳理一下现有的一些思路。
首先,明确“AI出牌算法的目的是能够模拟人打牌时的思考过程”,所以我根据平时自己玩斗地主的游戏经验,将思考过程大致分成了三个部分:“看自己手中的牌”、“看别人打出的牌”和“我该怎么出牌”。
第一步:看自己手中的牌
如何让电脑知道自己拿了一手什么牌呢?我这里所说的“知道”并不只是让电脑获取到点数、花色这样的数据,然是在此基础上通过牌型分析生成一套出牌方案。这里,我们需要引进一个“手数”的概念,就是指在不被压的前提下,需要多少次出牌机会才能把手中的牌打光。由于不同的出牌方案,同样的一手牌,可能有好几个不同的手数。
1.1 牌型分析
下面这段代码并不是完整代码,是我从项目中截取部分直接复制过来的,写的有些粗糙,为的是能表达大概意思,具体的牌型判断规则可参考四人斗地主。
/* 最后的数字代表此类牌型可能打出的张数
判断牌组的类型:
-1: 不符合逻辑的牌
1: 单牌 ------------------------------------------------------------------------------1
2: 2张相同数字的牌(对子)---------------------------------------------------------------2
3: 3张相同数字的牌 ---------------------------------------------------------------------3
4: 4张相同数字的牌(炸弹)---------------------------------------------------------------4
5: 5张相同数字的牌(炸弹)---------------------------------------------------------------5
6: 6张相同数字的牌(炸弹)---------------------------------------------------------------6
7: 7张相同数字的牌(炸弹)---------------------------------------------------------------7
8: 8张相同数字的牌(炸弹)---------------------------------------------------------------8
9: 2张大王带2张小王(王炸)--------------------------------------------------------------4
10: 5张或5张以上数字连续的牌(顺子)-------------------------------------------------------5~13
11: 3张相同数字的牌带一对(三带二)--------------------------------------------------------5
12: 3个或3个以上连续的对子(姐妹对)-------------------------------------------------------6,8,10,……,26
13: 2个或2个以上连续的3张相同数字的牌(飞机)-----------------------------------------------6,9,12,……,30
14: 2个或2个以上连续的3张相同数字的牌带同样数量的连续的对子(飞机带翅膀)------------------------10,15,20,25,30
*/
// 判断单张
if (choose.length == 1){ // choose 代表被选中的牌,数组型,以下皆是
return 1;
}
// 判断对子
if (choose.length == 2){ // Math.floor(Poker._player1[c_player[i]]/10) 代表player1手中被选中的牌,i 代表被选中的牌中从小到大第i张,从0开始,以下皆是
if (Math.floor(Poker._player1[c_player[0]]/10) == Math.floor(Poker._player1[c_player[1]]/10) && Math.floor(Poker._player1[c_player[0]]/10) < 14) {
return 2;
}
}
// 判断三张相同的牌
if (choose.length == 3){
if (Math.floor(Poker._player1[c_player[0]]/10) == Math.floor(Poker._player1[c_player[1]]/10) && Math.floor(Poker._player1[c_player[1]]/10) == Math.floor(Poker._player1[c_player[2]]/10) && Math.floor(Poker._player1[c_player[0]]/10) < 14) {
return 3;
}
}
// 判断四张炸弹
if (choose.length ==