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

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

    牌型
      火箭:即双王(大王和小王),最大的牌。
      炸弹:四张点数相同的牌,如: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的构造过程。

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

    http://blog.csdn.net/fansunion/article/details/12516411

    /**
     * 游戏规则 牌的类型共有10种:
     *
     * 1. 单 2.对子 3.3不带 4.3带1 5.炸弹 6.顺子 7.4带2 8.连队 9.飞机 10.对王
     *
     * @author LeiWen@FansUnion.cn,http://FansUnion.cn,
     *         http://blog.csdn.net/FansUnion
     *
     */

    1.单

      /**
         * 判断牌是否为单
         *
         * @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

  • 相关阅读:
    Windows环境下 配置memcached (php)
    谈谈我是怎么学习PHP的(一)
    重编译Linux命令源代码
    php面向对象学习
    Windows文件系统漏洞
    十分钟能学会的框架,MVC+20个常用函数
    linux系统安装软件方法大全
    oracle基本操作
    MySQL的limit查询优化
    C# winform 可视化操作 Excel文件并读取数据
  • 原文地址:https://www.cnblogs.com/qitian1/p/6463555.html
Copyright © 2011-2022 走看看