请教斗地主中斗地主飞机带翅膀膀(3带2)牌型的算法

1075人阅读
斗地主算法牌型判断和出牌提示(3)
现在在公司实习用quick-coco2dx引擎写了斗地主,所有代码用lua脚本实现。我把算法封装成了一个lua类(CardUtils)所有代码可以直接拿来使用。
首先先弄清楚有那些牌型:
火箭or王炸:即双王(大王和小王),最大的牌。
& & & & 炸弹:四张同数值牌(如四个 7 )。
& & & & 单牌:单个牌(如红桃 5 )。
& & & & 对牌:数值相同的两张牌(如梅花 4+ 方块 4 )。
& & & & 三张牌:数值相同的三张牌(如三个 J )。
& & & & 三带一:数值相同的三张牌 + 一张单牌或一对牌。例如: 333+6 或 444+99&
& & & & 单顺:五张或更多的连续单牌(如: 45678 或 78910JQK )。不包括 2 点和双王。
& & & & 双顺:三对或更多的连续对牌(如: 334455 、 JJ )。不包括 2 点和双王。&
& & & &三顺:二个或更多的连续三张牌(如: 333444 、
)。不包括 2 点和双王。
& & & & 飞机带翅膀:三顺+同数量的单牌(或同数量的对牌)。&
& & & & 如: ;79 或 +7799JJ&
& & & & 四带二:四张牌+两手牌。(注意:四带二不是炸弹)。
& 如: 5555 + 3 + 8 或 4444 + 55 + 77 。
这里我按照牌型的大小定义了一些变量方便在以后代码中使用
----各种牌型的对应数字
ERROR_CARDS = 0 --错误牌型
SINGLE_CARD = 1 --单牌
DOUBLE_CARD = 2 --对子
THREE_CARD = 3 --3不带
THREE_ONE_CARD = 4 --3带1
THREE_TWO_CARD = 5 --3带2
BOMB_TWO_CARD = 6 --四个带2张单牌
BOMB_FOUR_CARD = 7 --四个带2对
CONNECT_CARD = 8 --连牌
COMPANY_CARD = 9 --连队
AIRCRAFT_CARD = 10 --飞机不带
AIRCRAFT_WING = 11 --飞机带单牌或对子
BOMB_CARD = 12 --炸弹
KINGBOMB_CARD = 13 --王炸先来定义数字代表扑克中的牌的规则
我用3到13代表扑克中的3到K,再用14代表A,15 代表 2 (这样在以后的牌型判断和比较的时候方便)。花色用百位来表示(如方块3就是103,黑桃2就是415),大小王是116,117。
先写两个方法得到数字代表的牌值和花色
--获得扑克牌的牌值
function getValue(card)
return card % 100
--获得扑克牌的花色
function getSuit(card)
return card / 100
end在写一个方法判断数字是否是牌(有时候传进来的数字可能去掉了花色)
--测试所有的牌是否都是扑克牌
function isCards(cards)
for k,c in pairs(cards) do
if c & 100 then
17 & c then
return false
if getValue(c) & 17 or getValue(c) & 3 then
return false
return true
接下来就是牌型判断了先判断几个容易的牌型(牌数小于5的)
把所有的代表牌的数字放在一个table中传进去得到一个牌值的table
function getCardsTabValue(cards)
local tmp = {}
for k, v in pairs(cards or {}) do
if type(v) ~= &table& then
tmp[k] = v % 100
tmp[k] = CardUtils.getCardsTabValue(v)
return tmp
注意下面所有的判断都是先将数字去掉花色之后的判断
function isSingle(cards)
if not CardUtils.isCards(cards)then
return false
if 1 == #cards then
return true
return false
function isDouble(cards)
if not CardUtils.isCards(cards) then
return false
if 2 == #cards then
if cards[1] == cards[2] then
return true
return false
function isKingBomb(cards)
if not CardUtils.isCards(cards) or 2 ~= #cards then
return false
table.sort(cards)
if cards[1] == 16 and cards[2] == 17 then
return true
return false
--3不带 只要判断三个牌值相等
function isThree(cards)
if not CardUtils.isCards(cards) or 3 ~= #cards then
return false
if cards[1] == cards[2] and cards[1] == cards[3] then
return true
return false
--3带1 先对数字排序 再判断带的牌是在那个位置 ()再将带的牌移除判断剩下的三个牌是不是 3不带
function isThreeOne(cards)
if not CardUtils.isCards(cards) or 4 ~= #cards then
return false
table.sort(cards)
if cards[1] ~=cards[2] then
table.remove(cards, 1)
table.remove(cards, 4)
if isThree(cards)
return true
return false
先排序 头尾都是对子而且中间的牌等于头或者尾的值(5)
function isThreeTwo( cards )
if not CardUtils.isCards(cards) or 5 ~= #cards then
return false
table.sort(cards)
if cards[1] == cards[2] and cards[4] == cards[5] then
if cards[3] == cards[2] or cards[3] == cards[4] then
return true
return false
function isBomb( cards )
if not CardUtils.isCards(cards) or 4 ~= #cards then
return false
if cards[1] == cards[2] and cards[2] == cards[3] and cards[3] == cards[4] then
return true
return false
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:45597次
排名:千里之外
原创:31篇
转载:58篇
(1)(2)(1)(2)(1)(2)(5)(4)(2)(9)(7)(14)(8)(4)(1)(10)(3)(5)(4)(5)(1)3347人阅读
中国象棋-斗地主(19)
本篇主要讲解斗地主中如何比较两手牌的大小。友情提示:本篇是接着以下两篇文章就讲解的,建议先看看下面这2篇。牌型比较  火箭最大;炸弹次之;再次是一般牌型(单牌、对牌、三张牌、三带一、单顺、双顺、三顺、飞机带翅膀、四带二)  一般牌型:只有牌型且张数相同的牌才可按牌点数比较大小。  其中三带一、飞机带翅膀、四带二组合牌型,比较其相同张数最多的牌点数大小。1.比较我的牌和上家的牌的大小,决定是否可以出牌/**
* 比较我的牌和上家的牌的大小,决定是否可以出牌
* @param myCards
我想出的牌
* @param myCardType
我的牌的类型
* @param prevCards
* @param prevCardType
上家的牌型
* @return 可以出牌,返回true;否则,返回false。
public static boolean isOvercomePrev(List&Card& myCards,
CardType myCardType, List&Card& prevCards, CardType prevCardType) {
// 我的牌和上家的牌都不能为null
if (myCards == null || prevCards == null) {
if (myCardType == null || prevCardType == null) {
(&上家出的牌不合法,所以不能出。&);
// 上一首牌的个数
int prevSize = prevCards.size();
int mySize = myCards.size();
// 我先出牌,上家没有牌
if (prevSize == 0 && mySize != 0) {
// 集中判断是否王炸,免得多次判断王炸
if (prevCardType == CardType.WANG_ZHA) {
(&上家王炸,肯定不能出。&);
} else if (myCardType == CardType.WANG_ZHA) {
(&我王炸,肯定能出。&);
// 集中判断对方不是炸弹,我出炸弹的情况
if (prevCardType != CardType.ZHA_DAN && myCardType == CardType.ZHA_DAN) {
// 默认情况:上家和自己想出的牌都符合规则
CardUtil.sortCards(myCards);// 对牌排序
CardUtil.sortCards(prevCards);// 对牌排序
int myGrade = myCards.get(0).
int prevGrade = prevCards.get(0).
// 比较2家的牌,主要有2种情况,1.我出和上家一种类型的牌,即对子管对子;
// 2.我出炸弹,此时,和上家的牌的类型可能不同
// 王炸的情况已经排除
if (prevCardType == CardType.DAN && myCardType == CardType.DAN) {
// 一张牌可以大过上家的牌
return compareGrade(myGrade, prevGrade);
else if (prevCardType == CardType.DUI_ZI
&& myCardType == CardType.DUI_ZI) {
// 2张牌可以大过上家的牌
return compareGrade(myGrade, prevGrade);
else if (prevCardType == CardType.SAN_BU_DAI
&& myCardType == CardType.SAN_BU_DAI) {
// 3张牌可以大过上家的牌
return compareGrade(myGrade, prevGrade);
else if (prevCardType == CardType.ZHA_DAN
&& myCardType == CardType.ZHA_DAN) {
// 4张牌可以大过上家的牌
return compareGrade(myGrade, prevGrade);
else if (prevCardType == CardType.SAN_DAI_YI
&& myCardType == CardType.SAN_DAI_YI) {
// 3带1只需比较第2张牌的大小
myGrade = myCards.get(1).
prevGrade = prevCards.get(1).
return compareGrade(myGrade, prevGrade);
else if (prevCardType == CardType.SI_DAI_ER
&& myCardType == CardType.SI_DAI_ER) {
// 4带2只需比较第3张牌的大小
myGrade = myCards.get(2).
prevGrade = prevCards.get(2).
else if (prevCardType == CardType.SHUN_ZI
&& myCardType == CardType.SHUN_ZI) {
if (mySize != prevSize) {
// 顺子只需比较最大的1张牌的大小
myGrade = myCards.get(mySize - 1).
prevGrade = prevCards.get(prevSize - 1).
return compareGrade(myGrade, prevGrade);
else if (prevCardType == CardType.LIAN_DUI
&& myCardType == CardType.LIAN_DUI) {
if (mySize != prevSize) {
// 顺子只需比较最大的1张牌的大小
myGrade = myCards.get(mySize - 1).
prevGrade = prevCards.get(prevSize - 1).
return compareGrade(myGrade, prevGrade);
else if (prevCardType == CardType.FEI_JI
&& myCardType == CardType.FEI_JI) {
if (mySize != prevSize) {
// 顺子只需比较第5张牌的大小(特殊情况没有考虑,即12张的飞机,可以有2种出法)
myGrade = myCards.get(4).
prevGrade = prevCards.get(4).
return compareGrade(myGrade, prevGrade);
// 默认不能出牌
2.判断我所有的牌中,是否存在能够管住上家的牌,决定出牌按钮是否显示&&
* 判断我所有的牌中,是否存在能够管住上家的牌,决定出牌按钮是否显示
* @param myCards
我所有的牌 *
* @param prevCards
* @param prevCardType
上家牌的类型
* @return 可以出牌,返回true;否则,返回false。
public static boolean isOvercomePrev(List&Card& myCards,
List&Card& prevCards, CardType prevCardType) {
// 我的牌和上家的牌都不能为null
if (myCards == null || prevCards == null) {
if (prevCardType == null) {
System.out.println(&上家出的牌不合法,所以不能出。&);
// 默认情况:上家和自己想出的牌都符合规则
CardUtil.sortCards(myCards);// 对牌排序
CardUtil.sortCards(prevCards);// 对牌排序
// 上一首牌的个数
int prevSize = prevCards.size();
int mySize = myCards.size();
// 我先出牌,上家没有牌
if (prevSize == 0 && mySize != 0) {
// 集中判断是否王炸,免得多次判断王炸
if (prevCardType == CardType.WANG_ZHA) {
System.out.println(&上家王炸,肯定不能出。&);
if (mySize &= 2) {
List&Card& cards = new ArrayList&Card&();
cards.add(new Card(myCards.get(mySize - 1).id));
cards.add(new Card(myCards.get(mySize - 2).id));
if (isDuiWang(cards)) {
// 集中判断对方不是炸弹,我出炸弹的情况
if (prevCardType != CardType.ZHA_DAN) {
if (mySize & 4) {
for (int i = 0; i & mySize - 3; i++) {
int grade0 = myCards.get(i).
int grade1 = myCards.get(i + 1).
int grade2 = myCards.get(i + 2).
int grade3 = myCards.get(i + 3).
if (grade1 == grade0 && grade2 == grade0
&& grade3 == grade0) {
int prevGrade = prevCards.get(0).
// 比较2家的牌,主要有2种情况,1.我出和上家一种类型的牌,即对子管对子;
// 2.我出炸弹,此时,和上家的牌的类型可能不同
// 王炸的情况已经排除
// 上家出单
if (prevCardType == CardType.DAN) {
// 一张牌可以大过上家的牌
for (int i = mySize - 1; i &= 0; i--) {
int grade = myCards.get(i).
if (grade & prevGrade) {
// 只要有1张牌可以大过上家,则返回true
// 上家出对子
else if (prevCardType == CardType.DUI_ZI) {
// 2张牌可以大过上家的牌
for (int i = mySize - 1; i &= 1; i--) {
int grade0 = myCards.get(i).
int grade1 = myCards.get(i - 1).
if (grade0 == grade1) {
if (grade0 & prevGrade) {
// 只要有1对牌可以大过上家,则返回true
// 上家出3不带
else if (prevCardType == CardType.SAN_BU_DAI) {
// 3张牌可以大过上家的牌
for (int i = mySize - 1; i &= 2; i--) {
int grade0 = myCards.get(i).
int grade1 = myCards.get(i - 1).
int grade2 = myCards.get(i - 2).
if (grade0 == grade1 && grade0 == grade2) {
if (grade0 & prevGrade) {
// 只要3张牌可以大过上家,则返回true
// 上家出3带1
else if (prevCardType == CardType.SAN_DAI_YI) {
// 3带1 3不带 比较只多了一个判断条件
if (mySize & 4) {
// 3张牌可以大过上家的牌
for (int i = mySize - 1; i &= 2; i--) {
int grade0 = myCards.get(i).
int grade1 = myCards.get(i - 1).
int grade2 = myCards.get(i - 2).
if (grade0 == grade1 && grade0 == grade2) {
if (grade0 & prevGrade) {
// 只要3张牌可以大过上家,则返回true
// 上家出炸弹
else if (prevCardType == CardType.ZHA_DAN) {
// 4张牌可以大过上家的牌
for (int i = mySize - 1; i &= 3; i--) {
int grade0 = myCards.get(i).
int grade1 = myCards.get(i - 1).
int grade2 = myCards.get(i - 2).
int grade3 = myCards.get(i - 3).
if (grade0 == grade1 && grade0 == grade2 && grade0 == grade3) {
if (grade0 & prevGrade) {
// 只要有4张牌可以大过上家,则返回true
// 上家出4带2
else if (prevCardType == CardType.SI_DAI_ER) {
// 4张牌可以大过上家的牌
for (int i = mySize - 1; i &= 3; i--) {
int grade0 = myCards.get(i).
int grade1 = myCards.get(i - 1).
int grade2 = myCards.get(i - 2).
int grade3 = myCards.get(i - 3).
if (grade0 == grade1 && grade0 == grade2 && grade0 == grade3) {
// 只要有炸弹,则返回true
// 上家出顺子
else if (prevCardType == CardType.SHUN_ZI) {
if (mySize & prevSize) {
for (int i = mySize - 1; i &= prevSize - 1; i--) {
List&Card& cards = new ArrayList&Card&();
for (int j = 0; j & prevS j++) {
cards.add(new Card(myCards.get(i - j).grade));
CardType myCardType = getCardType(cards);
if (myCardType == CardType.SHUN_ZI) {
int myGrade2 = cards.get(cards.size() - 1).// 最大的牌在最后
int prevGrade2 = prevCards.get(prevSize - 1).// 最大的牌在最后
if (myGrade2 & prevGrade2) {
// 上家出连对
else if (prevCardType == CardType.LIAN_DUI) {
if (mySize & prevSize) {
for (int i = mySize - 1; i &= prevSize - 1; i--) {
List&Card& cards = new ArrayList&Card&();
for (int j = 0; j & prevS j++) {
cards.add(new Card(myCards.get(i - j).grade));
CardType myCardType = getCardType(cards);
if (myCardType == CardType.LIAN_DUI) {
int myGrade2 = cards.get(cards.size() - 1).// 最大的牌在最后,getCardType会对列表排序
int prevGrade2 = prevCards.get(prevSize - 1).// 最大的牌在最后
if (myGrade2 & prevGrade2) {
// 上家出飞机
else if (prevCardType == CardType.FEI_JI) {
if (mySize & prevSize) {
for (int i = mySize - 1; i &= prevSize - 1; i--) {
List&Card& cards = new ArrayList&Card&();
for (int j = 0; j & prevS j++) {
cards.add(new Card(myCards.get(i - j).grade));
CardType myCardType = getCardType(cards);
if (myCardType == CardType.FEI_JI) {
int myGrade4 = cards.get(4).//
int prevGrade4 = prevCards.get(4).//
if (myGrade4 & prevGrade4) {
// 默认不能出牌
3.比较2个grade的大小/**
* 比较2个grade的大小
* @param grade1
* @param grade2
private static boolean compareGrade(int grade1, int grade2) {
return grade1 & grade2;
4.检测牌的类型
* 检测牌的类型
* @param myCards
* @return 如果遵守规则,返回牌的类型,否则,返回null。
public static CardType getCardType(List&Card& myCards) {
CardType cardType =
if (myCards != null) {
// 大概率事件放前边,提高命中率
if (isDan(myCards)) {
cardType = CardType.DAN;
} else if (isDuiWang(myCards)) {
cardType = CardType.WANG_ZHA;
} else if (isDuiZi(myCards)) {
cardType = CardType.DUI_ZI;
} else if (isZhaDan(myCards)) {
cardType = CardType.ZHA_DAN;
} else if (isSanDaiYi(myCards) != -1) {
cardType = CardType.SAN_DAI_YI;
} else if (isSanBuDai(myCards)) {
cardType = CardType.SAN_BU_DAI;
} else if (isShunZi(myCards)) {
cardType = CardType.SHUN_ZI;
} else if (isLianDui(myCards)) {
cardType = CardType.LIAN_DUI;
} else if (isSiDaiEr(myCards)) {
cardType = CardType.SI_DAI_ER;
} else if (isFeiJi(myCards)) {
cardType = CardType.FEI_JI;
return cardT
未来计划接下来2篇将讲述 如何对牌进行排序,如何构造一副牌、洗牌、发牌。本周日 日上传所有源码。&相关阅读面向对象实现斗地主程序的核心算法,包括洗牌、发牌、判断牌型、比较牌的大小、游戏规则等。原文参见:
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:1966717次
积分:33904
积分:33904
排名:第110名
原创:993篇
转载:32篇
评论:3344条
微信:FansUnion
姓名:雷文
昵称:小雷FansUnion
籍贯:湖北-襄阳-枣阳
大学:武汉科技大学-软件工程08级-WUST
文章:30篇
阅读:62214
文章:11篇
阅读:29788
文章:14篇
阅读:58338
阅读:27047
文章:34篇
阅读:122069
阅读:27806
文章:16篇
阅读:44167
(16)(21)(21)(12)(20)(27)(6)(17)(21)(17)(4)(28)(36)(48)(1)(7)(10)(2)(14)(19)(24)(21)(43)(62)(51)(21)(16)(1)(7)(13)(2)(1)(1)(9)(42)(50)(48)(27)(16)(16)(3)(6)(9)(4)(9)(67)(26)(18)(71)400-100-5570
微信公众号
抵制不良游戏
注意自我保护
适度游戏益脑
合理安排时间
拒绝盗版游戏
谨防受骗上当
沉迷游戏伤身
享受健康生活
"斗地主"是流行于湖北一带的一种扑克游戏,玩法简单,娱乐性强,老少皆宜。
据传在万恶的旧社会,地主横行乡里,无恶不作,人们为了发泄对地主的痛恨,常常在一天的劳作之后,一家人关起门来"斗地主"。
该游戏由三个人玩一副牌,地主为一方,其余两家另为一方,双方对战,先出完手中牌的一方胜。
参与人数:3人
游戏用牌:一副牌,去掉大小王、四3个2,一个A 共48张,每人16张。(牌中无大小王)
出牌顺序:系统随意指定
出牌规则:逆时针出牌。
上家出的牌,下家有出必出,放走包赔。(放走规则:当下家报单,如果选择出单张,必须为手牌中的最大牌,否则视为放走,需包赔所有输分)。
炸弹赢取当圈的玩家即刻可获得由另2位玩家给予的喜金。(被炸死的炸弹不给予喜金)。
玩家手里只有一张牌的时候报警提示。
单张:1张任意牌,2最大,3最小。
对子:2张点数相同的牌,AA最大,33最小。
3带X:3同张可带2张或1对;接牌时,必须按上家的3+2张
顺子:点数相连的5张及以上的牌,可以从3连到A。如:910JQKA。
连对:点数相连的2张及以上的对子,可以从3连到A。如:。
三顺:点数相连的2个及以上的3同张,可以从3连到A。如:888999。(可带单牌或两对)
飞机带翅膀:点数相连的2个及以上的3同张,可以从3连到A。可带2张或2对,如:连3个3同张,,可选择带6张牌,也可以选择带3对牌。连2个3同张,333444,可选择带4张牌,也可带2对牌。
炸弹:4张相同点数的牌。如: 6666;炸弹的大小和牌点大小规则相同。
4带X:当玩家选择四张带牌的时候,四张不算炸弹,无法获得炸弹规则中的额外奖励。四带N可最多可带3张牌也可带2对牌。
火箭最大,可以打任意其他的牌。
炸弹比火箭小,比其他牌型大。都是炸弹时按牌的分值比较大小。
除火箭和炸弹外,其他牌必须要牌型相同且张数相同才能比较大小。
单牌按分值比大小,依次是大王、小王、2、A、K、Q、J、10、9、8、7、6、5、4、3,不区分花色。
对牌、三张牌都按分值比大小。
顺牌按最大的一张牌的分值来比大小。
飞机带翅膀和四带二按其中的三顺和四张部分来比大小,带的牌不影响大小。
任意一家出完牌后结束游戏,最先出完牌的为赢家。
斗地主采用一打二打法,地主输赢为农民的两倍。
斗地主采用底分×倍数的计分办法,底分为叫牌的分数,倍数为每局打出的炸弹和火箭数目的总和。
春天或是反春,翻倍计算。
游戏币要求
服务直通车
扫一扫关注零点棋牌公众号
扫一扫下载超级3D捕鱼

我要回帖

更多关于 斗地主飞机带对子算法 的文章

 

随机推荐