首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件开发 >

斗地主算法的设计与实现-怎么判断一手牌的类型(单,对子,三不带,三带一,四代二等)

2013-10-11 
斗地主算法的设计与实现--如何判断一手牌的类型(单,对子,三不带,三带一,四代二等)本篇主要讲解斗地主中如

斗地主算法的设计与实现--如何判断一手牌的类型(单,对子,三不带,三带一,四代二等)

本篇主要讲解斗地主中如何判断一手牌的牌型。

牌型
  火箭:即双王(大王和小王),最大的牌。
  炸弹:四张点数相同的牌,如:7777。
  单牌:任意一张单牌。
  对牌:任意两张点数相同的牌。
  三张:任意三张点数相同的牌,如888。
  三带一:点数相同的三张牌+一张单牌或一对牌。如:333+6 或 444+99。
  单顺:任意五张或五张以上点数相连的牌,如:45678或78910JQK。不包括 2和双王。
  双顺:三对或更多的连续对牌,如:334455、7788991010JJ。不包括 2 点和双王。
  三顺:二个或更多的连续三张牌,如:333444 、555666777888。不包括 2 点和双王。
  飞机带翅膀:三顺+同数量的单牌或同数量的对牌。如:444555+79 或333444555+7799JJ
  四带二:四张牌+两手牌。(注意:四带二不是炸弹)。如:5555+3+8 或 4444+55+77 。


友情提示:本篇是接着上1篇讲述的,建议先看看上1篇一张牌Card的构造过程。

/** * 判断牌是否为单 * * @param myCards * 牌的集合 * @return 如果为单,返回true;否则,返回false。 */ public static boolean isDan(List<Card> myCards) { // 默认不是单 boolean flag = false; if (myCards != null && myCards.size() == 1) { flag = true; } return flag; }


2.对子

    

/**     * 判断牌是否为对子     *     * @param myCards     *            牌的集合     * @return 如果为对子,返回true;否则,返回false。     */    public static boolean isDuiZi(List<Card> myCards) {        // 默认不是对子        boolean flag = false;        if (myCards != null && myCards.size() == 2) {            int grade1 = myCards.get(0).grade;            int grade2 = myCards.get(1).grade;            if (grade1 == grade2) {                flag = true;            }        }        return flag;    }


3.3带1

    /**
  

  * 判断牌是否为3带1     *     * @param myCards     *            牌的集合     * @return 如果为3带1,被带牌的位置,0或3,否则返回-1。炸弹返回-1。     */    public static int isSanDaiYi(List<Card> myCards) {        int flag = -1;        // 默认不是3带1        if (myCards != null && myCards.size() == 4) {            // 对牌进行排序            CardUtil.sortCards(myCards);            int[] grades = new int[4];            grades[0] = myCards.get(0).grade;            grades[1] = myCards.get(1).grade;            grades[2] = myCards.get(2).grade;            grades[3] = myCards.get(3).grade;            // 暂时认为炸弹不为3带1            if ((grades[1] == grades[0]) && (grades[2] == grades[0])                    && (grades[3] == grades[0])) {                return -1;            }            // 3带1,被带的牌在牌头            else if ((grades[1] == grades[0] && grades[2] == grades[0])) {                return 0;            }            // 3带1,被带的牌在牌尾            else if (grades[1] == grades[3] && grades[2] == grades[3]) {                return 3;            }        }        return flag;    }


4.3不带

  

 /**     * 判断牌是否为3不带     *     * @param myCards     *            牌的集合     * @return 如果为3不带,返回true;否则,返回false。     */    public static boolean isSanBuDai(List<Card> myCards) {        // 默认不是3不带        boolean flag = false;        if (myCards != null && myCards.size() == 3) {            int grade0 = myCards.get(0).grade;            int grade1 = myCards.get(1).grade;            int grade2 = myCards.get(2).grade;            if (grade0 == grade1 && grade2 == grade0) {                flag = true;            }        }        return flag;    }


5.顺子

  

 /**     * 判断牌是否为顺子     *     * @param myCards     *            牌的集合     * @return 如果为顺子,返回true;否则,返回false。     */    public static boolean isShunZi(List<Card> myCards) {        // 默认是顺子        boolean flag = true;        if (myCards != null) {            int size = myCards.size();            // 顺子牌的个数在5到12之间            if (size < 5 || size > 12) {                return false;            }            // 对牌进行排序            CardUtil.sortCards(myCards);            for (int n = 0; n < size - 1; n++) {                int prev = myCards.get(n).grade;                int next = myCards.get(n + 1).grade;                // 小王、大王、2不能加入顺子                if (prev == 17 || prev == 16 || prev == 15 || next == 17                        || next == 16 || next == 15) {                    flag = false;                    break;                } else {                    if (prev - next != -1) {                        flag = false;                        break;                    }                }            }        }        return flag;    }


6.炸弹

    

/**     * 判断牌是否为炸弹     *     * @param myCards     *            牌的集合     * @return 如果为炸弹,返回true;否则,返回false。     */    public static boolean isZhaDan(List<Card> myCards) {        // 默认不是炸弹        boolean flag = false;        if (myCards != null && myCards.size() == 4) {            int[] grades = new int[4];            grades[0] = myCards.get(0).grade;            grades[1] = myCards.get(1).grade;            grades[2] = myCards.get(2).grade;            grades[3] = myCards.get(3).grade;            if ((grades[1] == grades[0]) && (grades[2] == grades[0])                    && (grades[3] == grades[0])) {                flag = true;            }        }        return flag;    }


7.王炸

  

  /**     * 判断牌是否为王炸     *     * @param myCards     *            牌的集合     * @return 如果为王炸,返回true;否则,返回false。     */    public static boolean isDuiWang(List<Card> myCards) {        // 默认不是对王        boolean flag = false;        if (myCards != null && myCards.size() == 2) {            int gradeOne = myCards.get(0).grade;            int gradeTwo = myCards.get(1).grade;            // 只有小王和大王的等级之后才可能是33            if (gradeOne + gradeTwo == 33) {                flag = true;            }        }        return flag;    }


8.连对

 

   /**     * 判断牌是否为连对     *     * @param myCards     *            牌的集合     * @return 如果为连对,返回true;否则,返回false。     */    public static boolean isLianDui(List<Card> myCards) {        // 默认是连对        boolean flag = true;        if (myCards == null) {            flag = false;            return flag;        }                int size = myCards.size();        if (size < 6 || size % 2 != 0) {            flag = false;        } else {            // 对牌进行排序            CardUtil.sortCards(myCards);            for (int i = 0; i < size; i = i + 2) {                if (myCards.get(i).grade != myCards.get(i + 1).grade) {                    flag = false;                    break;                }                if (i < size - 2) {                    if (myCards.get(i).grade - myCards.get(i + 2).grade != -1) {                        flag = false;                        break;                    }                }            }        }        return flag;    }


9.飞机

 

   /**     * 判断牌是否为飞机     *     * @param myCards     *            牌的集合     * @return 如果为飞机,返回true;否则,返回false。     */    public static boolean isFeiJi(List<Card> myCards) {        boolean flag = false;        // 默认不是单        if (myCards != null) {            int size = myCards.size();            if (size >= 6) {                // 对牌进行排序                CardUtil.sortCards(myCards);                if (size % 3 == 0 && size % 4 != 0) {                    flag = isFeiJiBuDai(myCards);                } else if (size % 3 != 0 && size % 4 == 0) {                    flag = isFeiJiDai(myCards);                } else if (size == 12) {                    flag = isFeiJiBuDai(myCards) || isFeiJiDai(myCards);                }            }        }        return flag;    }


10.飞机不带

 

   /**     * 判断牌是否为飞机不带     *     * @param myCards     *            牌的集合     * @return 如果为飞机不带,返回true;否则,返回false。     */    public static boolean isFeiJiBuDai(List<Card> myCards) {        if (myCards == null) {            return false;        }        int size = myCards.size();        int n = size / 3;        int[] grades = new int[n];        if (size % 3 != 0) {            return false;        } else {            for (int i = 0; i < n; i++) {                if (!isSanBuDai(myCards.subList(i * 3, i * 3 + 3))) {                    return false;                } else {                    // 如果连续的3张牌是一样的,记录其中一张牌的grade                    grades[i] = myCards.get(i * 3).grade;                }            }        }        for (int i = 0; i < n - 1; i++) {            if (grades[i] == 15) {// 不允许出现2                return false;            }            if (grades[i + 1] - grades[i] != 1) {                System.out.println("等级连续,如 333444"                        + (grades[i + 1] - grades[i]));                return false;// grade必须连续,如 333444            }        }        return true;    }


11.飞机带

  

 /**     * 判断牌是否为飞机带     *     * @param myCards     *            牌的集合     * @return 如果为飞机带,返回true;否则,返回false。     */    public static boolean isFeiJiDai(List<Card> myCards) {        int size = myCards.size();        int n = size / 4;// 此处为“除”,而非取模        int i = 0;        for (i = 0; i + 2 < size; i = i + 3) {            int grade1 = myCards.get(i).grade;            int grade2 = myCards.get(i + 1).grade;            int grade3 = myCards.get(i + 2).grade;            if (grade1 == grade2 && grade3 == grade1) {                // return isFeiJiBuDai(myCards.subList(i, i + 3 *                // n));8张牌时,下标越界,subList不能取到最后一个元素                ArrayList<Card> cards = new ArrayList<Card>();                for (int j = i; j < i + 3 * n; j++) {// 取字串                    cards.add(myCards.get(j));                }                return isFeiJiBuDai(cards);            }        }        return false;    }


12.4带2

  

  /**     * 判断牌是否为4带2     *     * @param myCards     *            牌的集合     * @return 如果为4带2,返回true;否则,返回false。     */    public static boolean isSiDaiEr(List<Card> myCards) {        boolean flag = false;        if (myCards != null && myCards.size() == 6) {            // 对牌进行排序            CardUtil.sortCards(myCards);            for (int i = 0; i < 3; i++) {                int grade1 = myCards.get(i).grade;                int grade2 = myCards.get(i + 1).grade;                int grade3 = myCards.get(i + 2).grade;                int grade4 = myCards.get(i + 3).grade;                if (grade2 == grade1 && grade3 == grade1 && grade4 == grade1) {                    flag = true;                }            }        }        return flag;    }


下一篇,将要介绍 如何比较2手牌的大小,敬请期待。

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

6楼i_like_cpp昨天 22:17
算法不错呀。
Re: FansUnion昨天 22:42
回复i_like_cppn多谢啊。n期待下一篇。
5楼zdp072昨天 20:24
支持一下..
Re: FansUnion昨天 21:07
回复zdp072n多谢。源码周末上传。(*^__^*) 嘻嘻
4楼ssergsw昨天 13:00
楼主果然高产呀~必须支持
Re: FansUnion昨天 13:10
回复ssergswn这种文章还是挺好写的。n代码,注释,思路 我做过的项目都总结好了。n发表出来,只要做好排版,理清思路,让读者能够很容易看懂罢了。nn纯文字型的思想深刻,见解独到的文章,才是难写的。n慢慢来。
Re: ssergsw昨天 13:12
回复FansUnionn我是做安全的,文章就不太好拿摄,写多了容易引起小网站被攻击的风险,写少了内行觉得恶心,外行完全看不明白。。。
Re: FansUnion昨天 13:35
回复ssergswn那就不写安全相关的呗。n写作话题还是蛮多的,工作、生活、技术 好多好多了...
3楼FansUnion昨天 12:59
加上详细的注释,不用再做太多说明,很多人都看得懂。n即使是初学者,我觉得只要打过斗地主,应该都看得懂吧。n(*^__^*) nn多多支持啊。
2楼zay109327402昨天 12:53
isZhaDan 这种函数名看着令人忧桑
Re: FansUnion昨天 12:56
回复zay109327402n怎么了?中英文结合的函数名字么?n“炸弹”等很多名字 都要翻译成 英文,太麻烦了。
1楼FansUnion昨天 12:25
斗地主算法-第3篇n斗地主算法的设计与实现--如何比较两手牌的大小n已经写好了,明天发表,周末上传源码。

热点排行