任务35:后端-对出牌进行牌型判断与出牌规则逻辑
回顾下Type中牌型:\Server\ET.Core\Landlords\Component\Type.cs
/// <summary> /// 出牌类型 /// </summary> public enum CardsType { None, JokerBoom, //王炸 Boom, //炸弹 OnlyThree, //三张 ThreeAndOne, //三带一 ThreeAndTwo, //三带二 Straight, //顺子 五张或更多的连续单牌 DoubleStraight, //双顺 三对或更多的连续对牌 TripleStraight, //三顺 二个或更多的连续三张牌 Double, //对子 Single //单牌 }
梳理下CardHelper提供的几个关键方法
- public static async Task<List<Card[]>> GetPrompt 获取提示出牌
-
public static bool PopEnable 判断牌型与出牌规则
-
public static void SortCards 牌组排序
-
public static int GetWeight 获取牌组权重
MapHelper添加出牌辅助类CardHelper,类中添加上面这静态些方法 \Server\Hotfix\Helper\MapHelper.cs
记得MapHelper上面加上新的using
using System.Threading.Tasks; using System.Linq;
/// <summary> /// 斗地主出牌辅助方法 /// </summary> public static class CardHelper { }
判断牌型与出牌规则PopEnable
/// <summary> /// 判断是否符合出牌规则 /// </summary> public static bool PopEnable(Card[] cards, out CardsType type) { type = CardsType.None; bool isRule = false; switch (cards?.Length) { case 1: isRule = true; type = CardsType.Single; break; case 2: if (IsDouble(cards)) { isRule = true; type = CardsType.Double; } else if (IsJokerBoom(cards)) { isRule = true; type = CardsType.JokerBoom; } break; case 3: if (IsOnlyThree(cards)) { isRule = true; type = CardsType.OnlyThree; } break; case 4: if (IsBoom(cards)) { isRule = true; type = CardsType.Boom; } else if (IsThreeAndOne(cards)) { isRule = true; type = CardsType.ThreeAndOne; } break; case 5: if (IsStraight(cards)) { isRule = true; type = CardsType.Straight; } else if (IsThreeAndTwo(cards)) { isRule = true; type = CardsType.ThreeAndTwo; } break; case 6: if (IsStraight(cards)) { isRule = true; type = CardsType.Straight; } else if (IsTripleStraight(cards)) { isRule = true; type = CardsType.TripleStraight; } else if (IsDoubleStraight(cards)) { isRule = true; type = CardsType.DoubleStraight; } break; case 7: if (IsStraight(cards)) { isRule = true; type = CardsType.Straight; } break; case 8: if (IsStraight(cards)) { isRule = true; type = CardsType.Straight; } else if (IsDoubleStraight(cards)) { isRule = true; type = CardsType.DoubleStraight; } break; case 9: if (IsStraight(cards)) { isRule = true; type = CardsType.Straight; } else if (IsOnlyThree(cards)) { isRule = true; type = CardsType.OnlyThree; } break; case 10: if (IsStraight(cards)) { isRule = true; type = CardsType.Straight; } else if (IsDoubleStraight(cards)) { isRule = true; type = CardsType.DoubleStraight; } break; case 11: if (IsStraight(cards)) { isRule = true; type = CardsType.Straight; } break; case 12: if (IsStraight(cards)) { isRule = true; type = CardsType.Straight; } else if (IsDoubleStraight(cards)) { isRule = true; type = CardsType.DoubleStraight; } else if (IsOnlyThree(cards)) { isRule = true; type = CardsType.OnlyThree; } break; case 13: break; case 14: if (IsDoubleStraight(cards)) { isRule = true; type = CardsType.DoubleStraight; } break; case 15: if (IsOnlyThree(cards)) { isRule = true; type = CardsType.OnlyThree; } break; case 16: if (IsDoubleStraight(cards)) { isRule = true; type = CardsType.DoubleStraight; } break; case 17: break; case 18: if (IsDoubleStraight(cards)) { isRule = true; type = CardsType.DoubleStraight; } else if (IsOnlyThree(cards)) { isRule = true; type = CardsType.OnlyThree; } break; case 19: break; case 20: if (IsDoubleStraight(cards)) { isRule = true; type = CardsType.DoubleStraight; } break; default: break; } return isRule; }
具体牌型判断方法
/// <summary> /// 是否是单 /// </summary> public static bool IsSingle(Card[] cards) { if (cards.Length == 1) return true; else return false; } /// <summary> /// 是否是对子 /// </summary> public static bool IsDouble(Card[] cards) { if (cards.Length == 2) { if (cards[0].CardWeight == cards[1].CardWeight) return true; } return false; } /// <summary> /// 是否是顺子 /// </summary> public static bool IsStraight(Card[] cards) { if (cards.Length < 5 || cards.Length > 12) return false; for (int i = 0; i < cards.Length - 1; i++) { int w = cards[i].CardWeight; if (w - cards[i + 1].CardWeight != 1) return false; //不能超过A if (w > (int)Weight.One || cards[i + 1].CardWeight > (int)Weight.One) return false; } return true; } /// <summary> /// 是否是双顺子 /// </summary> public static bool IsDoubleStraight(Card[] cards) { if (cards.Length < 6 || cards.Length % 2 != 0) return false; for (int i = 0; i < cards.Length; i += 2) { if (cards[i + 1].CardWeight != cards[i].CardWeight) return false; if (i < cards.Length - 2) { if (cards[i].CardWeight - cards[i + 2].CardWeight != 1) return false; //不能超过A if (cards[i].CardWeight > (int)Weight.One || cards[i + 2].CardWeight > (int)Weight.One) return false; } } return true; } /// <summary> /// 飞机不带 /// </summary> public static bool IsTripleStraight(Card[] cards) { if (cards.Length < 6 || cards.Length % 3 != 0) return false; for (int i = 0; i < cards.Length; i += 3) { if (cards[i + 1].CardWeight != cards[i].CardWeight) return false; if (cards[i + 2].CardWeight != cards[i].CardWeight) return false; if (cards[i + 1].CardWeight != cards[i + 2].CardWeight) return false; if (i < cards.Length - 3) { if (cards[i].CardWeight - cards[i + 3].CardWeight != 1) return false; //不能超过A if (cards[i].CardWeight > (int)Weight.One || cards[i + 3].CardWeight > (int)Weight.One) return false; } } return true; } /// <summary> /// 三不带 /// </summary> public static bool IsOnlyThree(Card[] cards) { if (cards.Length % 3 != 0) return false; if (cards[0].CardWeight != cards[1].CardWeight) return false; if (cards[1].CardWeight != cards[2].CardWeight) return false; if (cards[0].CardWeight != cards[2].CardWeight) return false; return true; } /// <summary> /// 三带一 /// </summary> public static bool IsThreeAndOne(Card[] cards) { if (cards.Length != 4) return false; if (cards[0].CardWeight == cards[1].CardWeight && cards[1].CardWeight == cards[2].CardWeight) return true; else if (cards[1].CardWeight == cards[2].CardWeight && cards[2].CardWeight == cards[3].CardWeight) return true; return false; } /// <summary> /// 三代二 /// </summary> public static bool IsThreeAndTwo(Card[] cards) { if (cards.Length != 5) return false; if (cards[0].CardWeight == cards[1].CardWeight && cards[1].CardWeight == cards[2].CardWeight) { if (cards[3].CardWeight == cards[4].CardWeight) return true; } else if (cards[2].CardWeight == cards[3].CardWeight && cards[3].CardWeight == cards[4].CardWeight) { if (cards[0].CardWeight == cards[1].CardWeight) return true; } return false; } /// <summary> /// 炸弹 /// </summary> public static bool IsBoom(Card[] cards) { if (cards.Length != 4) return false; if (cards[0].CardWeight != cards[1].CardWeight) return false; if (cards[1].CardWeight != cards[2].CardWeight) return false; if (cards[2].CardWeight != cards[3].CardWeight) return false; return true; } /// <summary> /// 王炸 /// </summary> public static bool IsJokerBoom(Card[] cards) { if (cards.Length != 2) return false; if (cards[0].CardWeight == (int)Weight.SJoker) { if (cards[1].CardWeight == (int)Weight.LJoker) return true; return false; } else if (cards[0].CardWeight == (int)Weight.LJoker) { if (cards[1].CardWeight == (int)Weight.SJoker) return true; return false; } return false; }
获取提示出牌 GetPrompt
/// <summary> /// 获取提示出牌 /// </summary> public static async Task<List<Card[]>> GetPrompt(List<Card> cards, DeskCardsCacheComponent deskCardsCache, CardsType type) { List<Card[]> result = new List<Card[]>(); Card[] deskCards = deskCardsCache.GetAll(); int weight = deskCardsCache.GetTotalWeight(); if (type == CardsType.JokerBoom) { return result; } //检索王炸 if (cards.Count >= 2) { Card[] groupCards = new Card[2]; groupCards[0] = cards[0]; groupCards[1] = cards[1]; if (IsJokerBoom(groupCards)) { result.Add(groupCards); } } //检索炸弹 for (int i = cards.Count - 1; i >= 3; i--) { Card[] groupCards = new Card[4]; groupCards[0] = cards[i - 3]; groupCards[1] = cards[i - 2]; groupCards[2] = cards[i - 1]; groupCards[3] = cards[i]; if (IsBoom(groupCards) && GetWeight(groupCards, CardsType.Boom) > weight) { result.Add(groupCards); } } switch (type) { case CardsType.OnlyThree: for (int i = cards.Count - 1; i >= 2; i--) { if (cards[i].CardWeight <= deskCards[deskCards.Length - 1].CardWeight) { continue; } Card[] groupCards = new Card[3]; groupCards[0] = cards[i - 2]; groupCards[1] = cards[i - 1]; groupCards[2] = cards[i]; if (IsOnlyThree(groupCards) && GetWeight(groupCards, type) > weight) { result.Add(groupCards); } } break; case CardsType.ThreeAndOne: if (cards.Count >= 4) { for (int i = cards.Count - 1; i >= 2; i--) { if (cards[i].CardWeight <= deskCards[deskCards.Length - 1].CardWeight) { continue; } List<Card> other = new List<Card>(cards); other.RemoveRange(i - 2, 3); Card[] groupCards = new Card[4]; groupCards[0] = cards[i - 2]; groupCards[1] = cards[i - 1]; groupCards[2] = cards[i]; groupCards[3] = other[RandomHelper.RandomNumber(0, other.Count)]; if (IsThreeAndOne(groupCards) && GetWeight(groupCards, type) > weight) { result.Add(groupCards); } } } break; case CardsType.ThreeAndTwo: if (cards.Count >= 5) { for (int i = cards.Count - 1; i >= 2; i--) { if (cards[i].CardWeight <= deskCards[deskCards.Length - 1].CardWeight) { continue; } List<Card> other = new List<Card>(cards); other.RemoveRange(i - 2, 3); List<Card[]> otherDouble = await GetPrompt(other, deskCardsCache, CardsType.Double); if (otherDouble.Count > 0) { Card[] randomDouble = otherDouble[RandomHelper.RandomNumber(0, otherDouble.Count)]; Card[] groupCards = new Card[5]; groupCards[0] = cards[i - 2]; groupCards[1] = cards[i - 1]; groupCards[2] = cards[i]; groupCards[3] = randomDouble[0]; groupCards[4] = randomDouble[1]; if (IsThreeAndTwo(groupCards) && GetWeight(groupCards, type) > weight) { result.Add(groupCards); } } } } break; case CardsType.Straight: /* * 7 6 5 4 3 * 8 7 6 5 4 * * */ if (cards.Count >= deskCards.Length) { for (int i = cards.Count - 1; i >= deskCards.Length - 1; i--) { if (cards[i].CardWeight <= deskCards[deskCards.Length - 1].CardWeight) { continue; } //是否全部搜索完成 bool isTrue = true; Card[] groupCards = new Card[deskCards.Length]; for (int j = 0; j < deskCards.Length; j++) { //搜索连续权重牌 Card findCard = cards.Where(card => (int)card.CardWeight == (int)cards[i].CardWeight + j).FirstOrDefault(); if (findCard == null) { isTrue = false; break; } groupCards[deskCards.Length - 1 - j] = findCard; } if (isTrue && IsStraight(groupCards) && GetWeight(groupCards, type) > weight) { result.Add(groupCards); } } } break; case CardsType.DoubleStraight: /* * 5 5 4 4 3 3 * 6 6 5 5 4 4 * * */ if (cards.Count >= deskCards.Length) { for (int i = cards.Count - 1; i >= deskCards.Length - 1; i--) { if (cards[i].CardWeight <= deskCards[deskCards.Length - 1].CardWeight) { continue; } //是否全部搜索完成 bool isTrue = true; Card[] groupCards = new Card[deskCards.Length]; for (int j = 0; j < deskCards.Length; j += 2) { //搜索连续权重牌 Card[] findCards = cards.Where(card => (int)card.CardWeight == (int)cards[i].CardWeight + (j / 2)).ToArray(); if (findCards.Length < 2) { isTrue = false; break; } groupCards[deskCards.Length - 2 - j] = findCards[0]; groupCards[deskCards.Length - 1 - j] = findCards[1]; } if (isTrue && IsDoubleStraight(groupCards) && GetWeight(groupCards, type) > weight) { result.Add(groupCards); } } } break; case CardsType.TripleStraight: if (cards.Count >= deskCards.Length) { for (int i = cards.Count - 1; i >= deskCards.Length - 1; i--) { if (cards[i].CardWeight <= deskCards[deskCards.Length - 1].CardWeight) { continue; } //是否全部搜索完成 bool isTrue = true; Card[] groupCards = new Card[deskCards.Length]; for (int j = 0; j < deskCards.Length; j += 3) { //搜索连续权重牌 Card[] findCards = cards.Where(card => (int)card.CardWeight == (int)cards[i].CardWeight + (j / 3)).ToArray(); if (findCards.Length < 3) { isTrue = false; break; } groupCards[deskCards.Length - 3 - j] = findCards[0]; groupCards[deskCards.Length - 2 - j] = findCards[1]; groupCards[deskCards.Length - 1 - j] = findCards[2]; } if (isTrue && IsTripleStraight(groupCards) && GetWeight(groupCards, type) > weight) { result.Add(groupCards); } } } break; case CardsType.Double: if (cards.Count >= 2) { for (int i = cards.Count - 1; i >= 1; i--) { Card[] groupCards = new Card[2]; groupCards[0] = cards[i - 1]; groupCards[1] = cards[i]; if (IsDouble(groupCards) && GetWeight(groupCards, type) > weight) { result.Add(groupCards); } } } break; case CardsType.Single: if (cards.Count >= 1) { for (int i = cards.Count - 1; i >= 0; i--) { if (cards[i].CardWeight <= deskCards[deskCards.Length - 1].CardWeight) { continue; } Card[] groupCards = new Card[1]; groupCards[0] = cards[i]; if (IsSingle(groupCards) && GetWeight(groupCards, type) > weight) { result.Add(groupCards); } } } break; default: break; } return result; }
GetWeight 获取牌组权重与SortCards 牌组排序
/// <summary> /// 获取牌组权重 /// </summary> public static int GetWeight(Card[] cards, CardsType rule) { int totalWeight = 0; if (rule == CardsType.JokerBoom) { totalWeight = int.MaxValue; } else if (rule == CardsType.Boom) { totalWeight = (int)cards[0].CardWeight * (int)cards[1].CardWeight * (int)cards[2].CardWeight * (int)cards[3].CardWeight + (int.MaxValue / 2); } else if (rule == CardsType.ThreeAndOne || rule == CardsType.ThreeAndTwo) { for (int i = 0; i < cards.Length; i++) { if (i < cards.Length - 2) { if (cards[i].CardWeight == cards[i + 1].CardWeight && cards[i].CardSuits == cards[i + 2].CardSuits) { totalWeight += (int)cards[i].CardWeight; totalWeight *= 3; break; } } } } else { for (int i = 0; i < cards.Length; i++) { totalWeight += (int)cards[i].CardWeight; } } return totalWeight; } /// <summary> /// 牌组排序 /// </summary> public static void SortCards(List<Card> cards) { cards.Sort( (Card a, Card b) => { //先按照权重降序,再按花色升序 return -a.CardWeight.CompareTo(b.CardWeight) * 2 + a.CardWeight.CompareTo(b.CardWeight); } ); }
斗地主的核心算法都在这里了,你需要用开发者的思维理清楚斗地主的玩法规则,具体的牌型判断方法代码与注释都很清晰,好好思考都能明白。
本节主要是出牌算法与逻辑,大家自行消化,下节我们实现了前端的请求后再测试效果。