对于所有类似斗地主这种卡牌类游戏, 其实游戏思路都是差不多的. 先判断出牌是否是'有效牌型', 若是, 再判断该牌型的权重值用来比较大小. 本篇文章将介绍如何实现一个斗地主的卡牌游戏引擎, 洗牌, 发牌, 牌型检查并比较大小. 核心代码比较完整, 后面给了一个 GUI 的 demo, 完成了洗牌, 发牌, 选牌出牌, 牌型检查, 但是没有实现电脑自动出牌的功能, 有兴趣的可以 down 下来看一下.
Github 源码 https://github.com/sherlockchou86/fucklandlord
实现思路
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://www.cnblogs.com/xiaozhi_5638/p/9138626.html