zoukankan      html  css  js  c++  java
  • 自己实现斗地主引擎

    对于所有类似斗地主这种卡牌类游戏,其实游戏思路都是差不多的。先判断出牌是否是‘有效牌型’,若是,再判断该牌型的权重值用来比较大小。本篇文章将介绍如何实现一个斗地主的卡牌游戏引擎,洗牌、发牌、牌型检查并比较大小。核心代码比较完整,后面给了一个GUI的demo,完成了洗牌、发牌、选牌出牌,牌型检查,但是没有实现电脑自动出牌的功能,有兴趣的可以down下来看一下。

    Github源码 

    实现思路

    1)根据斗地主规则,罗列出所有可能出现的牌型。比如‘单张’、‘对子’、‘三连对’、‘五连顺’、‘六连顺’、‘飞机’、‘炸弹’等等。一共37种牌型;

    2)对于上面的37种牌型,每种牌型又存在多种情况,对于‘单张’而言,存在3、4、A、2、小王、大王等等,并且其权重值依次增大。同理,对于‘五连顺’而言,存在3-4-5-6-7、4-5-6-7-8...10-J-Q-K-A等等,并且其权重值依次增大。枚举出所有细分牌型,并为其赋予权重值,下一次就会以O(1)的时间复杂度快速判断输入卡牌是否是有效牌型;

    3)在斗地主游戏中,默认只有相同牌型才能比较大小(比较其权重值),但是‘炸弹’牌型(四张相同的卡牌或者一对王)是个例外;

    4)斗地主游戏中,不分花色。所以一对‘红桃A+黑桃A’跟一对‘梅花A+方块A’是一样大的。因此在引擎计算中,需要先将所有有花色的输入卡牌,全部去除花色,然后再计算;

    数据字典初始化

    以‘K-Q-Q-Q-K-K-Q-K’输入手牌为例(输入手牌可以无序),存在以下数据字典:

    [Key]       ==>  K-K-K-K-Q-Q-Q-Q(降序排序,保证key唯一)

    [Values]  ==> 

                 {Display=K-K-K-K-Q-Q-Q-Q,  Name=四带两对,     Weight=300}

                 {Display=Q-Q-Q-Q-K-K-K-K,  Name=四带两对,     Weight=200}

                 {Display=K-K-K-Q-Q-Q-K-Q,  Name=飞机带两张”,  Weight=300}

    对于同一个输入手牌,对应三种牌型。对于任何输入,都能通过O(1)时间复杂度判断该输入是否有效,若有效,返回对应牌型数据(可以包含多个,绿色部分为相同牌型,可以比较大小)。

    数据字典初始化需要一定时间,本机测试大约耗时5秒。关于牌型检查这里,通过机器学习应该可以快速判断出牌型,但是并不能得出其对应的权重值,要想得到权重值,还是需要通过枚举(有疑问?)

    卡牌定义

    4种花色

            /// <summary>
            /// 4 colors
            /// diamonds, clubs, hearts, spades
            /// </summary>
            public static List<String> CardColors = new List<string> {"D", "C", "H", "S" };

    15张不带花色卡牌

            /// <summary>
            /// 15 kinds of card without color
            /// 3, 4, 5, 6, 7, 8, 9, 10, Jack, Queen, King, Ace, 2, Little joker, Big joker
            /// </summary>
            public static List<String> CardValues = new List<string> {"3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K", "A", "2", "LJ", "BJ" };

    54张全部带花色卡牌(‘K*H’代表‘红桃K’,‘4*D’代表‘方块4’)

            /// <summary>
            /// return all cards with color in the game
            /// 3*D 3*C 3*H 3*S 4*D 4*C 4*H 4*S 5*D 5*C 5*H 5*S  ... 2*D 2*C 2*H 2*S LJ BJ 
            /// </summary>
            public static List<String> Cards
            {
                get
                {
                    List<String> cards = new List<string>();
    
                    // 13*4==52
                    for (int index = 0; index < 13; index++ )
                    {
                        foreach (String card_color in CardColors)
                        {
                            cards.Add(CardValues[index] + "*" + card_color);  //  value*color
                        }
                    }
    
                    // 52+2 == 54
                    cards.Add(CardValues[13]);
                    cards.Add(CardValues[14]);
    
                    return cards;
                }
            }

    洗牌

    随机打乱54张带花色卡牌,并以List<String>的形式返回

            /// <summary>
            /// shuffle the cards. 
            /// </summary>
            /// <returns>a list of 54 cards. has color but disordered.</returns>
            public List<String> Shuffle()
            {
                List<String> cards = EngineValues.Cards;
    
                Random rand = new Random(Guid.NewGuid().GetHashCode());
                List<String> newList = new List<String>();
    
                foreach (String card in cards)
                {
                    newList.Insert(rand.Next(0, newList.Count), card);
                }
    
                // need reorder the first element
                newList.Remove(cards[0]);
                newList.Insert(rand.Next(0, newList.Count), cards[0]);
    
                return newList;
            }

    发牌

    传入5个参数,分别是:

    • 洗完牌后的list(作为输入, 54张)
    • 第一个人发牌list(作为输出, 17张)
    • 第二个人发牌list(作为输出, 17张)
    • 第三个人发牌list(作为输出, 17张)
    • 底牌list(作为输出, 3张)
            /// <summary>
            /// deal the cards to 3 parts, 17 cards(such as A*H, BJ, 4*D ...) for each part, another 3 cards will be asigned to the guy who is the landlord.
            /// </summary>
            /// <param name="original_cards">the original cards list, returned by Shuffle method.</param>
            /// <param name="first">the first part</param>
            /// <param name="second">the second part</param>
            /// <param name="third">the third part</param>
            /// <param name="last_cards">the last 3 cards</param>
            /// <returns>true if deal successfully</returns>
            public bool Deal(List<String> original_cards, List<String> first, List<String> second, List<String> third, List<String> last_cards)
            {
                // check if the parameters are valid
                if (original_cards == null 
                    || original_cards.Count != 54
                    || first == null
                    || first.Count != 0
                    || second == null
                    || second.Count != 0
                    || third == null
                    || third.Count != 0
                    || last_cards == null
                    || last_cards.Count != 0)
                {
                    return false;
                }
    
                // simulate player catch the card, everyone has 17 times.
                for (int index = 0; index < 17; index++)
                {
                    first.Add(original_cards[index * 3]);
                    second.Add(original_cards[index * 3 + 1]);
                    third.Add(original_cards[index * 3 + 2]);
                }
                
                // the last 3 cards
                last_cards.Add(original_cards[51]);
                last_cards.Add(original_cards[52]);
                last_cards.Add(original_cards[53]);
    
                return true;
            }

    检查牌型

    根据输入手牌,直接通过数据字典查询,返回结果中包含对应权重值。

    public List<CardType> Check(List<String> input)
    {
        //format the input, remove color if it has, sort the card
        String formated_input = EngineTool.FormatCardStr(String.Join("-", input));
        List<CardType> result = new List<CardType>();
        if (EngineValues.Set.ContainsKey(formated_input))
        {
            result.AddRange(EngineValues.Set[formated_input]);
        }
        return result;
    }

  • 相关阅读:
    Java Spring Boot VS .NetCore (十) Java Interceptor vs .NetCore Interceptor
    Java Spring Boot VS .NetCore (九) Spring Security vs .NetCore Security
    IdentityServer4 And AspNetCore.Identity Get AccessToken 问题
    Java Spring Boot VS .NetCore (八) Java 注解 vs .NetCore Attribute
    Java Spring Boot VS .NetCore (七) 配置文件
    Java Spring Boot VS .NetCore (六) UI thymeleaf vs cshtml
    Java Spring Boot VS .NetCore (五)MyBatis vs EFCore
    Java Spring Boot VS .NetCore (四)数据库操作 Spring Data JPA vs EFCore
    Java Spring Boot VS .NetCore (三)Ioc容器处理
    Java Spring Boot VS .NetCore (二)实现一个过滤器Filter
  • 原文地址:https://www.cnblogs.com/xiaozhi_5638/p/9138626.html
Copyright © 2011-2022 走看看