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


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

    友情提示:本篇是接着以下两篇文章就讲解的,建议先看看下面这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

  • 相关阅读:
    ASCII,Unicode 和 UTF-8
    ASCII,Unicode 和 UTF-8
    043_JVM——JVM是什么鬼啊?他与操作系统是什么关系?
    042_杂谈——编程语言的发展
    042_线程——我们写的代码,为什么我从来没有线程呢?
    041_ssm——/与/*与*.do的区别?
    040_HTTP——为什么会有get与post两种请求?
    039_Servlet——SpringMVC中怎么不见Servlet呢?我们写的Controller都是普通类,Servlet藏到了那里?
    038_JVM——怎么查看对象的内存大小?
    037_JVM——java中的类加载器是怎么运行的?
  • 原文地址:https://www.cnblogs.com/riasky/p/3363446.html
Copyright © 2020-2023  润新知