为了账号安全,请及时绑定邮箱和手机立即绑定

自己实现斗地主引擎

标签:
算法

对于所有类似斗地主这种卡牌类游戏,其实游戏思路都是差不多的。先判断出牌是否是‘有效牌型’,若是,再判断该牌型的权重值用来比较大小。本篇文章将介绍如何实现一个斗地主的卡牌游戏引擎,洗牌、发牌、牌型检查并比较大小。核心代码比较完整,后面给了一个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;}

 

https://img1.sycdn.imooc.com//5b166a090001eab509790512.jpg

https://img1.sycdn.imooc.com//5b166a140001ac1d08710629.jpg

 

作者:周见智
出处:http://www.cnblogs.com/xiaozhi_5638/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消