本篇主要讲解斗地主中如何比较两手牌的大小。

友情提示:本篇是接着以下两篇文章就讲解的,建议先看看下面这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) {
return false;
} if (myCardType == null || prevCardType == null) {
logger.info("上家出的牌不合法,所以不能出。");
return false;
} // 上一首牌的个数
int prevSize = prevCards.size();
int mySize = myCards.size(); // 我先出牌,上家没有牌
if (prevSize == 0 && mySize != 0) {
return true;
} // 集中判断是否王炸,免得多次判断王炸
if (prevCardType == CardType.WANG_ZHA) {
logger.info("上家王炸,肯定不能出。");
return false;
} else if (myCardType == CardType.WANG_ZHA) {
logger.info("我王炸,肯定能出。");
return true;
} // 集中判断对方不是炸弹,我出炸弹的情况
if (prevCardType != CardType.ZHA_DAN && myCardType == CardType.ZHA_DAN) {
return true;
} // 默认情况:上家和自己想出的牌都符合规则
CardUtil.sortCards(myCards);// 对牌排序
CardUtil.sortCards(prevCards);// 对牌排序 int myGrade = myCards.get(0).grade;
int prevGrade = prevCards.get(0).grade; // 比较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); }
// 3不带
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); }
// 3带1
else if (prevCardType == CardType.SAN_DAI_YI
&& myCardType == CardType.SAN_DAI_YI) { // 3带1只需比较第2张牌的大小
myGrade = myCards.get(1).grade;
prevGrade = prevCards.get(1).grade;
return compareGrade(myGrade, prevGrade); }
// 4带2
else if (prevCardType == CardType.SI_DAI_ER
&& myCardType == CardType.SI_DAI_ER) { // 4带2只需比较第3张牌的大小
myGrade = myCards.get(2).grade;
prevGrade = prevCards.get(2).grade; }
// 顺子
else if (prevCardType == CardType.SHUN_ZI
&& myCardType == CardType.SHUN_ZI) {
if (mySize != prevSize) {
return false;
} else {
// 顺子只需比较最大的1张牌的大小
myGrade = myCards.get(mySize - 1).grade;
prevGrade = prevCards.get(prevSize - 1).grade;
return compareGrade(myGrade, prevGrade);
} }
// 连对
else if (prevCardType == CardType.LIAN_DUI
&& myCardType == CardType.LIAN_DUI) {
if (mySize != prevSize) {
return false;
} else {
// 顺子只需比较最大的1张牌的大小
myGrade = myCards.get(mySize - 1).grade;
prevGrade = prevCards.get(prevSize - 1).grade;
return compareGrade(myGrade, prevGrade);
} }
// 飞机
else if (prevCardType == CardType.FEI_JI
&& myCardType == CardType.FEI_JI) {
if (mySize != prevSize) {
return false;
} else {
// 顺子只需比较第5张牌的大小(特殊情况333444555666没有考虑,即12张的飞机,可以有2种出法)
myGrade = myCards.get(4).grade;
prevGrade = prevCards.get(4).grade;
return compareGrade(myGrade, prevGrade);
}
} // 默认不能出牌
return false;
}

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) {
return false;
} if (prevCardType == null) {
System.out.println("上家出的牌不合法,所以不能出。");
return false;
} // 默认情况:上家和自己想出的牌都符合规则
CardUtil.sortCards(myCards);// 对牌排序
CardUtil.sortCards(prevCards);// 对牌排序 // 上一首牌的个数
int prevSize = prevCards.size();
int mySize = myCards.size(); // 我先出牌,上家没有牌
if (prevSize == 0 && mySize != 0) {
return true;
} // 集中判断是否王炸,免得多次判断王炸
if (prevCardType == CardType.WANG_ZHA) {
System.out.println("上家王炸,肯定不能出。");
return false;
} 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)) {
return true;
}
} // 集中判断对方不是炸弹,我出炸弹的情况
if (prevCardType != CardType.ZHA_DAN) {
if (mySize < 4) {
return false;
} else {
for (int i = 0; i < mySize - 3; i++) {
int grade0 = myCards.get(i).grade;
int grade1 = myCards.get(i + 1).grade;
int grade2 = myCards.get(i + 2).grade;
int grade3 = myCards.get(i + 3).grade; if (grade1 == grade0 && grade2 == grade0
&& grade3 == grade0) {
return true;
}
}
} } int prevGrade = prevCards.get(0).grade; // 比较2家的牌,主要有2种情况,1.我出和上家一种类型的牌,即对子管对子;
// 2.我出炸弹,此时,和上家的牌的类型可能不同
// 王炸的情况已经排除 // 上家出单
if (prevCardType == CardType.DAN) {
// 一张牌可以大过上家的牌
for (int i = mySize - 1; i >= 0; i--) {
int grade = myCards.get(i).grade;
if (grade > prevGrade) {
// 只要有1张牌可以大过上家,则返回true
return true;
}
} }
// 上家出对子
else if (prevCardType == CardType.DUI_ZI) {
// 2张牌可以大过上家的牌
for (int i = mySize - 1; i >= 1; i--) {
int grade0 = myCards.get(i).grade;
int grade1 = myCards.get(i - 1).grade; if (grade0 == grade1) {
if (grade0 > prevGrade) {
// 只要有1对牌可以大过上家,则返回true
return true;
}
}
} }
// 上家出3不带
else if (prevCardType == CardType.SAN_BU_DAI) {
// 3张牌可以大过上家的牌
for (int i = mySize - 1; i >= 2; i--) {
int grade0 = myCards.get(i).grade;
int grade1 = myCards.get(i - 1).grade;
int grade2 = myCards.get(i - 2).grade; if (grade0 == grade1 && grade0 == grade2) {
if (grade0 > prevGrade) {
// 只要3张牌可以大过上家,则返回true
return true;
}
}
} }
// 上家出3带1
else if (prevCardType == CardType.SAN_DAI_YI) {
// 3带1 3不带 比较只多了一个判断条件
if (mySize < 4) {
return false;
} // 3张牌可以大过上家的牌
for (int i = mySize - 1; i >= 2; i--) {
int grade0 = myCards.get(i).grade;
int grade1 = myCards.get(i - 1).grade;
int grade2 = myCards.get(i - 2).grade; if (grade0 == grade1 && grade0 == grade2) {
if (grade0 > prevGrade) {
// 只要3张牌可以大过上家,则返回true
return true;
}
}
} }
// 上家出炸弹
else if (prevCardType == CardType.ZHA_DAN) {
// 4张牌可以大过上家的牌
for (int i = mySize - 1; i >= 3; i--) {
int grade0 = myCards.get(i).grade;
int grade1 = myCards.get(i - 1).grade;
int grade2 = myCards.get(i - 2).grade;
int grade3 = myCards.get(i - 3).grade; if (grade0 == grade1 && grade0 == grade2 && grade0 == grade3) {
if (grade0 > prevGrade) {
// 只要有4张牌可以大过上家,则返回true
return true;
}
}
} }
// 上家出4带2
else if (prevCardType == CardType.SI_DAI_ER) {
// 4张牌可以大过上家的牌
for (int i = mySize - 1; i >= 3; i--) {
int grade0 = myCards.get(i).grade;
int grade1 = myCards.get(i - 1).grade;
int grade2 = myCards.get(i - 2).grade;
int grade3 = myCards.get(i - 3).grade; if (grade0 == grade1 && grade0 == grade2 && grade0 == grade3) {
// 只要有炸弹,则返回true
return true;
}
}
}
// 上家出顺子
else if (prevCardType == CardType.SHUN_ZI) {
if (mySize < prevSize) {
return false;
} else {
for (int i = mySize - 1; i >= prevSize - 1; i--) {
List<Card> cards = new ArrayList<Card>();
for (int j = 0; j < prevSize; 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).grade;// 最大的牌在最后
int prevGrade2 = prevCards.get(prevSize - 1).grade;// 最大的牌在最后 if (myGrade2 > prevGrade2) {
return true;
}
}
}
} }
// 上家出连对
else if (prevCardType == CardType.LIAN_DUI) {
if (mySize < prevSize) {
return false;
} else {
for (int i = mySize - 1; i >= prevSize - 1; i--) {
List<Card> cards = new ArrayList<Card>();
for (int j = 0; j < prevSize; 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).grade;// 最大的牌在最后,getCardType会对列表排序
int prevGrade2 = prevCards.get(prevSize - 1).grade;// 最大的牌在最后 if (myGrade2 > prevGrade2) {
return true;
}
}
}
} }
// 上家出飞机
else if (prevCardType == CardType.FEI_JI) {
if (mySize < prevSize) {
return false;
} else {
for (int i = mySize - 1; i >= prevSize - 1; i--) {
List<Card> cards = new ArrayList<Card>();
for (int j = 0; j < prevSize; j++) {
cards.add(new Card(myCards.get(i - j).grade));
} CardType myCardType = getCardType(cards);
if (myCardType == CardType.FEI_JI) {
int myGrade4 = cards.get(4).grade;//
int prevGrade4 = prevCards.get(4).grade;// if (myGrade4 > prevGrade4) {
return true;
}
}
}
}
} // 默认不能出牌
return false;
}

3.比较2个grade的大小

/**
* 比较2个grade的大小
*
* @param grade1
* @param grade2
* @return
*/
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 = null;
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 cardType; }

未来计划

接下来2篇将讲述 如何对牌进行排序,如何构造一副牌、洗牌、发牌。

本周日 2013年10月13日上传所有源码。

原文参见:http://FansUnion.cn/articles/2729

斗地主算法的设计与实现--项目介绍&如何定义和构造一张牌的更多相关文章

  1. [置顶] 斗地主算法的设计与实现--项目介绍&如何定义和构造一张牌

    大学期间,我在别人的基础上,写了一个简易的斗地主程序. 主要实现了面向对象设计,洗牌.发牌.判断牌型.比较牌的大小.游戏规则等算法. 通过这个斗地主小项目的练习,提高了我的面向对象设计能力,加深了对算 ...

  2. 斗地主算法的设计与实现(一)--项目介绍&如何定义和构造一张牌

    大学期间,我在别人的基础上,写了一个简易的斗地主程序. 主要实现了面向对象设计,洗牌.发牌.判断牌型.比较牌的大小.游戏规则等算法. 通过这个斗地主小项目的练习,提高了我的面向对象设计能力,加深了对算 ...

  3. Java实验项目四——多线程矩阵相乘算法的设计

    Program:多线程矩阵相乘算法的设计 Description:利用多线程实现矩阵相乘,因为各个线程的运算互不影响, 所以不用使用锁,代码如下: thread.OperateMatrix类,实现矩阵 ...

  4. 6个P2P流媒体开源项目介绍

    P2P流媒体开源项目介绍  1. PeerCast 2002年成立,最早的开源P2P流媒体项目.PeerCast把节点按树结构组织起来, 每个频道都是一个树, 直播源是根节点,父节点只给子节点提供数据 ...

  5. P2P流媒体开源项目介绍

    P2P流媒体开源项目介绍1. PeerCast 2002年成立,最早的开源P2P流媒体项目.PeerCast把节点按树结构组织起来, 每个频道都是一个树, 直播源是根节点,父节点只给子节点提供数据.节 ...

  6. LVS项目介绍

    LVS项目介绍 章文嵩 (wensong@linux-vs.org) 转自LVS官方参考资料 2002 年 3 月 本文介绍了Linux服务器集群系统--LVS(Linux Virtual Serve ...

  7. Hadoop学习笔记—20.网站日志分析项目案例(一)项目介绍

    网站日志分析项目案例(一)项目介绍:当前页面 网站日志分析项目案例(二)数据清洗:http://www.cnblogs.com/edisonchou/p/4458219.html 网站日志分析项目案例 ...

  8. CoinPunk项目介绍

           CoinPunk是一个bitcoin比特币钱夹服务web应用程序,你可以自己构建钱夹服务.开源,免费. 轻量级,高效 响应式设计 轻易创建新账户 详细的交易记录 构建于Node.js与H ...

  9. 【斗地主技巧】斗地主算法逻辑中的天之道<转>

    ******************************************************************** 作者比较喜欢玩斗地主,所以经常搜集一些网友斗地主的心得,下面这 ...

随机推荐

  1. UITabBarController使用详解

    UITabBarController是IOS中很常用的一个viewController,例如系统的闹钟程序,ipod 程序等.UITabBarController通常作为整个程序的rootViewCo ...

  2. 设置dialog显示,自定义时间到后dialog消失

    方法一: public class MyDialog extends Dialog { private int FLAG_DISMISS = 1; private boolean flag = tru ...

  3. M记单刷鸡盒副本

    今天去M记单刷鸡盒副本,听说此副本掉落最新道具:黑暗之门.鸡翅区和鸡块区全通无压力,鸡腿区难度最大,老一是个灭团点.现在肚子很难受,刚去厕所吐了一把,看来有点高估自己,此副本最好还是组队前往,单刷压力 ...

  4. JAVA 可视化分析工具 第12节

    JAVA 可视化分析工具  第12节 经过前几章对堆内存以及垃圾收集机制的学习,相信小伙伴们已经建立了一套比较完整的理论体系!那么这章我们就根据已有的理论知识,通过可视化工具来实践一番. 我们今天要讲 ...

  5. skynet初学

    记录下命令 git clone https://github.com/cloudwu/skynet.git sudo apt-get install autoconf sudo apt-get ins ...

  6. asp.net core + angular2

    asp.net core + angular2 的环境配置 国内整个对 asp.net core  和 angular2这些新出来的关注度不是太好.跟国外比很大差距. 我在试着去做这个整合的时候也碰到 ...

  7. IZ65534: 'JAVA.LANG.CLASSFORMATERROR' ERROR FOR A VALID IDENTIFIER

    PAR status Closed as program error. Error description Error Message: The java class could not be loa ...

  8. Unix/Linux环境C编程入门教程(8) FreeBSD CCPP开发环境搭建

    1. FreeBSD是一种自由类Unix操作系统,是由经过BSD.386BSD和4.4BSD发展而来的类Unix的一个重要分支.FreeBSD拥有超过200名活跃开发者和上千名贡献者.FreeBSD被 ...

  9. C++实现Http Post请求

    参考资料: http://apps.hi.baidu.com/share/detail/39003388 http://blog.csdn.net/yc0188/article/details/474 ...

  10. 君子性非异也,善假于物也 - Threejs 引入TrackballControls 查看场景

    君子性非异也,善假于物也 - Threejs 引入TrackballControls 查看场景 太阳火神的漂亮人生 (http://blog.csdn.net/opengl_es) 本文遵循" ...