|
德州扑克是一种牌类游戏,可多人参与,它的玩法是,玩家每人发两张底牌,桌面依次发5张公共牌,玩家用自己的两张底牌和5张公共牌自由组合,按大小决定胜负。
使用c#完成功能Hand()以返回手牌类型和按重要性递减顺序排列的等级列表,用于与同类型的其他手牌进行比较,即最佳手牌。
可能的手牌按价值降序排列:
同花顺(同一套衣服的连续五个等级)。级别越高越好。
四张(四张等级相同的牌)。平局决胜先是等级,然后是剩余牌的等级。
满座(三张等级相同的牌,两张等级相同)。决胜局首先是三张牌的等级,然后是一对牌的等级。
同花顺(五张同花色的牌)。从高到低,级别越高越好。
直(连续五个等级)。级别越高越好。
三张牌(三张等级相同的牌)。决胜局是三张牌中排名第一的,然后是其他排名最高的,然后才是其他排名第二的。
两对(两张相同等级的牌,两张不同等级的牌)。决胜局首先是高牌对的等级,然后是低牌对的级别,然后是剩余牌的等级。
配对(两张等级相同的牌)。平局决胜是先是两张牌的等级,然后是其他三张牌的级别。
算法实现:- 1 using System;
- 2 using System.Collections.Generic;
- 3 using System.Linq;
- 4 using System.Text;
- 5
- 6 public static class Edm
- 7 {
- 8 public static (string type, string[] ranks) Hand(string[] holeCards, string[] communityCards)
- 9 {
- 10 Card[] allCards = holeCards.Concat(communityCards).Select( x=> new Card(x)).OrderByDescending(card =>card.value).ToArray();
- 11
- 12 var rulesChain = createChainOfCommand();
- 13 var powerhands = rulesChain.Execute(allCards);
- 14 return (powerhands.Item1, getReturnlist(allCards, powerhands.Item2));
- 15
- 16 }
- 17 public static string[] getReturnlist(Card[] cards, Card[] powerhand)
- 18 {
- 19 var remainderHand = cards.Where(x => !powerhand.Any(y => y.Equals(x))).Take(5-powerhand.Length);
- 20 var result = powerhand.Select(x =>x.number).Distinct().Concat(remainderHand.Select(x=>x.number)).Take(5).Select(x => x.ToString()).ToArray();
- 21 return result;
- 22 }
- 23
- 24 public static Rule createChainOfCommand()
- 25 {
- 26 Rule straightFlush = new StraightFlushRule();
- 27 Rule fourOfAKind = new FourOfAKindRule();
- 28 Rule fullHouse = new FullHouseRule();
- 29 Rule flush = new FlushRule();
- 30 Rule straight = new StraightRule();
- 31 Rule threeOfAKind = new ThreeOfAKindRule();
- 32 Rule pairTwoPair = new PairTwoPairRule();
- 33 straightFlush.SetSuccessor(fourOfAKind);
- 34 fourOfAKind.SetSuccessor(fullHouse);
- 35 fullHouse.SetSuccessor(flush);
- 36 flush.SetSuccessor(straight);
- 37 straight.SetSuccessor(threeOfAKind);
- 38 threeOfAKind.SetSuccessor(pairTwoPair);
- 39 return straightFlush;
- 40 }
- 41 }
- 42 public abstract class Rule
- 43 {
- 44 private Rule nextRule;
- 45 public void SetSuccessor(Rule next)
- 46 {
- 47 nextRule = next;
- 48 }
- 49 public virtual (string, Card[]) Execute(Card[] cards)
- 50 {
- 51 if (nextRule != null)
- 52 {
- 53 return nextRule.Execute(cards);
- 54 }
- 55 return ("nothing", cards.Take(5).ToArray());
- 56 }
- 57 }
- 58
- 59 public class PairTwoPairRule : Rule
- 60 {
- 61 public override (string, Card[]) Execute(Card[] cards)
- 62 {
- 63 var pairs = cards.GroupBy(x => x.number).Where(g => g.Count() >= 2).SelectMany(card => card).ToList();
- 64 if (pairs.Any())
- 65 {
- 66 if(pairs.Count() >= 4)
- 67 {
- 68 return ("two pair", pairs.Take(4).ToArray());
- 69 }
- 70 return ("pair", pairs.Take(2).ToArray());
- 71 }
- 72 return base.Execute(cards);
- 73 }
- 74 }
- 75 public class ThreeOfAKindRule : Rule
- 76 {
- 77 public override (string, Card[]) Execute(Card[] cards)
- 78 {
- 79 var triple = cards.GroupBy(x => x.number).Where(g => g.Count() >= 3).SelectMany(card => card).ToList();
- 80 if (triple.Any())
- 81 {
- 82 return ("three-of-a-kind", triple.Take(3).ToArray());
- 83 }
- 84 return base.Execute(cards);
- 85 }
- 86 }
- 87 public class StraightRule : Rule
- 88 {
- 89 public override (string, Card[]) Execute(Card[] cards)
- 90 {
- 91 for (int i = 0; i < cards.Length - 4; i++)
- 92 {
- 93 List<Card> rtnList = new List<Card>() { cards[i] }; // "A♥","J♦","10♥" "9♠", "9♥", "8♠", "7♣"
- 94 int counter = 4;
- 95 int j = i;
- 96 while (counter >= 0 && j < cards.Length - 1)
- 97 {
- 98 if (cards[j].value - cards[j + 1].value == 1)
- 99 {
- 100 rtnList.Add(cards[j + 1]);
- 101
- 102 if (rtnList.Count() == 5)
- 103 {
- 104 return ("straight", rtnList.ToArray());
- 105 }
- 106 counter--;
- 107 j++;
- 108 }
- 109 else if (cards[j].value - cards[j + 1].value == 0)
- 110 {
- 111 j++;
- 112 }
- 113 else
- 114 {
- 115 break;
- 116 }
- 117 }
- 118 }
- 119 return base.Execute(cards);
- 120 }
- 121 }
- 122 public class FlushRule : Rule
- 123 {
- 124 public override (string, Card[]) Execute(Card[] cards)
- 125 {
- 126 var flush = cards.GroupBy(x => x.suit).Where(g => g.Count() >= 5).SelectMany(card => card).ToList();
- 127 if (flush.Any())
- 128 {
- 129 return ("flush", flush.ToArray());
- 130 }
- 131 return base.Execute(cards);
- 132 }
- 133 }
- 134
- 135 public class FullHouseRule : Rule
- 136 {
- 137 public override (string, Card[]) Execute(Card[] cards)
- 138 {
- 139 var triple = new ThreeOfAKindRule();
- 140 var pair = new PairTwoPairRule();
- 141
- 142 var powerhands = triple.Execute(cards);
- 143 if (!powerhands.Item1.Equals("nothing"))
- 144 {
- 145 if (powerhands.Item2.Count() == 6) // then 2 three of a kind found
- 146 {
- 147 return ("full house", powerhands.Item2.Take(5).ToArray());
- 148 }
- 149 var remainderHand = cards.Where(x => !powerhands.Item2.Any(y => y.Equals(x))).ToArray();
- 150 var pairHand = pair.Execute(remainderHand);
- 151 if (!pairHand.Item1.Equals("nothing"))
- 152 {
- 153 var fullhouseHand = powerhands.Item2.Concat(pairHand.Item2.Take(2)).ToArray();
- 154 return ("full house", fullhouseHand.Take(5).ToArray());
- 155 }
- 156 }
- 157 return base.Execute(cards);
- 158 }
- 159 }
- 160 public class FourOfAKindRule : Rule
- 161 {
- 162 public override (string, Card[]) Execute(Card[] cards)
- 163 {
- 164 var fourOfAKind = cards.GroupBy(x => x.number).Where(g => g.Count() >= 4).SelectMany(card => card).ToList();
- 165 if (fourOfAKind.Any())
- 166 {
- 167 return ("four-of-a-kind", fourOfAKind.Take(4).ToArray());
- 168 }
- 169 return base.Execute(cards);
- 170 }
- 171 }
- 172 public class StraightFlushRule : Rule
- 173 {
- 174 public override (string, Card[]) Execute(Card[] cards)
- 175 {
- 176 var flushRule = new FlushRule();
- 177 var straightRule = new StraightRule();
- 178 var flushHand = flushRule.Execute(cards);
- 179 var straightHand = straightRule.Execute(flushHand.Item2);
- 180 if (!straightHand.Item1.Equals("nothing") && !flushHand.Item1.Equals("nothing"))
- 181 {
- 182 return ("straight-flush", straightHand.Item2.Take(5).ToArray());
- 183 }
- 184 return base.Execute(cards);
- 185 }
- 186 }
- 187
- 188 public class Card{
- 189 public String number { get; set; }
- 190 public int value { get; set; }
- 191 public char suit { get; set; }
- 192 public Dictionary<char, int> mapping = new Dictionary<char, int>()
- 193 {
- 194 { 'A',14 },
- 195 { 'K',13 },
- 196 { 'Q',12 },
- 197 { 'J',11 },
- 198 { '1', 10}
- 199 };
- 200 public Card(String s)
- 201 {
- 202 number = (s[0] == '1')? "10": Char.ToString(s[0]);
- 203 value = mapping.ContainsKey(s[0])? mapping[s[0]]: (int) Char.GetNumericValue(s[0]);
- 204 suit = s[s.Length-1];
- 205 }
- 206 public override string ToString()
- 207 {
- 208 return number.ToString();
- 209 }
- 210
- 211 public bool equals(Card s)
- 212 {
- 213 return this.value == s.value && this.suit.Equals(s.suit);
- 214 }
- 215 }
复制代码 测试用例:- 1 namespace Solution
- 2 {
- 3 using NUnit.Framework;
- 4 using System;
- 5 using System.Collections.Generic;
- 6 using System.Diagnostics;
- 7 using System.Linq;
- 8 using System.Text;
- 9
- 10 [TestFixture]
- 11 public class SolutionTest
- 12 {
- 13 #region Sample Tests
- 14
- 15 [Test(Description = "Fixed Tests")]
- 16 public void FixedTests()
- 17 {
- 18 SampleTest(("nothing", new[] { "A", "K", "Q", "J", "9" }), new[] { "K♠", "A♦" }, new[] { "J♣", "Q♥", "9♥", "2♥", "3♦" });
- 19 SampleTest(("pair", new[] { "Q", "K", "J", "9" }), new[] { "K♠", "Q♦" }, new[] { "J♣", "Q♥", "9♥", "2♥", "3♦" });
- 20 SampleTest(("two pair", new[] { "K", "J", "9" }), new[] { "K♠", "J♦" }, new[] { "J♣", "K♥", "9♥", "2♥", "3♦" });
- 21 SampleTest(("three-of-a-kind", new[] { "Q", "J", "9" }), new[] { "4♠", "9♦" }, new[] { "J♣", "Q♥", "Q♠", "2♥", "Q♦" });
- 22 SampleTest(("straight", new[] { "K", "Q", "J", "10", "9" }), new[] { "Q♠", "2♦" }, new[] { "J♣", "10♥", "9♥", "K♥", "3♦" });
- 23 SampleTest(("flush", new[] { "Q", "J", "10", "5", "3" }), new[] { "A♠", "K♦" }, new[] { "J♥", "5♥", "10♥", "Q♥", "3♥" });
- 24 SampleTest(("full house", new[] { "A", "K" }), new[] { "A♠", "A♦" }, new[] { "K♣", "K♥", "A♥", "Q♥", "3♦" });
- 25 SampleTest(("four-of-a-kind", new[] { "2", "3" }), new[] { "2♠", "3♦" }, new[] { "2♣", "2♥", "3♠", "3♥", "2♦" });
- 26 SampleTest(("straight-flush", new[] { "J", "10", "9", "8", "7" }), new[] { "8♠", "6♠" }, new[] { "7♠", "5♠", "9♠", "J♠", "10♠" });
- 27 }
- 28
- 29 private static void SampleTest((string type, string[] ranks) expected, string[] holeCards, string[] communityCards)
- 30 {
- 31 var actual = Act(holeCards, communityCards);
- 32 Verify(expected, actual, holeCards, communityCards);
- 33 }
- 34
- 35 #endregion
- 36
- 37 private static readonly StringBuilder template = new StringBuilder();
- 38 private static readonly StringBuilder buffer = new StringBuilder();
- 39 private static readonly string[] ranks = new string[] { "A", "K", "Q", "J", "10", "9", "8", "7", "6", "5", "4", "3", "2" };
- 40 private static readonly string[] types = new string[] { "straight-flush", "four-of-a-kind", "full house", "flush", "straight", "three-of-a-kind", "two pair", "pair", "nothing" };
- 41 private static readonly Dictionary<string, int> ranksLookup = ranks.ToDictionary(x => x, x => Array.FindIndex(ranks, y => y == x));
- 42 private static string Show(string str) => $@"""{str}""";
- 43 private static string ShowSeq(IEnumerable<string> seq) => $"[{string.Join(", ", seq.Select(Show))}]";
- 44 private static (string type, string[] ranks) Act(string[] holeCards, string[] communityCards) => Edm.Hand(holeCards.Select(m=>m).ToArray(), communityCards.Select(m=>m).ToArray());
- 45
- 46 private static string Error(string message)
- 47 {
- 48 buffer.Clear();
- 49 buffer.Append(template.ToString());
- 50 buffer.AppendLine($"Error: {message}");
- 51 return buffer.ToString();
- 52 }
- 53
- 54 private static void Verify(
- 55 (string type, string[] ranks) expected, (string type, string[] ranks) actual, string[] holeCards, string[] communityCards)
- 56 {
- 57 Debug.Assert(holeCards.Concat(communityCards).Distinct().Count() == 7, "Invalid input");
- 58 template.Clear();
- 59 template.AppendLine($"\tHole cards: {ShowSeq(holeCards)}");
- 60 template.AppendLine($"\tCommunity cards: {ShowSeq(communityCards)}");
- 61 template.AppendLine($"Expected: (type: {Show(expected.type)}, ranks: {ShowSeq(expected.ranks)})");
- 62 Assert.IsNotNull(actual.type, Error("Type must not be null"));
- 63 Assert.IsNotNull(actual.ranks, Error("Ranks must not be null"));
- 64 template.AppendLine($"Actual: (type: {Show(actual.type)}, ranks: {ShowSeq(actual.ranks)})");
- 65 Assert.IsTrue(types.Any(x => string.Equals(x, actual.type)),
- 66 Error($"{Show(actual.type)} is not valid, valid options are: {ShowSeq(types)}"));
- 67 Assert.AreEqual(expected.type, actual.type, Error("Type is incorrect"));
- 68 Assert.AreEqual(expected.ranks.Length, actual.ranks.Length, Error("Number of ranks is incorrect"));
- 69 for (var i = 0; i < expected.ranks.Length; i++)
- 70 Assert.IsTrue(ranks.Any(x => string.Equals(x, actual.ranks[i])),
- 71 Error($"{Show(actual.ranks[i])} is not valid, valid options are: {ShowSeq(ranks)}"));
- 72 for (var i = 0; i < expected.ranks.Length; i++)
- 73 Assert.AreEqual(expected.ranks[i], actual.ranks[i], Error($"Rank at position {i} is incorrect"));
- 74 }
- 75
- 76 #region Test Cases
- 77
- 78 private static readonly string[] suits = new string[] { "♠", "♦", "♥", "♣" };
- 79 private static Dictionary<string, int> stats = new Dictionary<string, int>();
- 80
- 81 [Test(Description = "Fixed Edge Case Tests")]
- 82 public void FixedEdgeCaseTests()
- 83 {
- 84 // ace low straight invalidated
- 85 SampleTest(("nothing", new[] { "A", "8", "7", "5", "4" }), new[] { "A♠", "2♦" }, new[] { "3♣", "4♥", "5♥", "7♥", "8♦" });
- 86 // non straight around
- 87 SampleTest(("nothing", new[] { "A", "K", "8", "7", "4" }), new[] { "A♠", "K♦" }, new[] { "3♣", "4♥", "2♥", "7♥", "8♦" });
- 88
- 89 // pair on board
- 90 SampleTest(("pair", new[] { "4", "A", "9", "7" }), new[] { "A♠", "2♦" }, new[] { "3♣", "4♥", "9♥", "7♥", "4♦" });
- 91 // pair made with 1 hole card
- 92 SampleTest(("pair", new[] { "4", "A", "10", "9" }), new[] { "A♠", "4♦" }, new[] { "3♣", "4♥", "9♥", "7♥", "10♦" });
- 93 // pair made with 2 hole cards
- 94 SampleTest(("pair", new[] { "4", "A", "10", "9" }), new[] { "4♠", "4♦" }, new[] { "3♣", "A♥", "9♥", "7♥", "10♦" });
- 95
- 96 // two pair on board
- 97 SampleTest(("two pair", new[] { "Q", "2", "K" }), new[] { "K♠", "J♦" }, new[] { "Q♣", "Q♥", "9♥", "2♥", "2♦" });
- 98 // two pair made with 1 hole card and 1 pair on board
- 99 SampleTest(("two pair", new[] { "Q", "2", "K" }), new[] { "K♠", "Q♦" }, new[] { "J♣", "Q♥", "9♥", "2♥", "2♦" });
- 100 // two pair made with 2 hole cards
- 101 SampleTest(("two pair", new[] { "Q", "2", "K" }), new[] { "2♠", "Q♦" }, new[] { "J♣", "Q♥", "9♥", "2♥", "K♦" });
- 102 // two pair made with pair in hole cards and 1 pair on board
- 103 SampleTest(("two pair", new[] { "Q", "2", "K" }), new[] { "Q♠", "Q♦" }, new[] { "K♣", "J♥", "9♥", "2♥", "2♦" });
- 104 // two pair made with 2 hole cards, invalidating a 3th pair on board
- 105 SampleTest(("two pair", new[] { "K", "J", "9" }), new[] { "K♠", "J♦" }, new[] { "J♣", "K♥", "9♥", "2♥", "2♦" });
- 106
- 107 // three-of-a-kind on board
- 108 SampleTest(("three-of-a-kind", new[] { "Q", "K", "J" }), new[] { "K♠", "J♦" }, new[] { "Q♣", "Q♥", "9♥", "2♥", "Q♦" });
- 109 // three-of-a-kind made with 1 hole card and 1 pair on board
- 110 SampleTest(("three-of-a-kind", new[] { "Q", "K", "J" }), new[] { "K♠", "Q♦" }, new[] { "Q♣", "Q♥", "9♥", "2♥", "J♦" });
- 111 // three-of-a-kind made with 2 hole cards
- 112 SampleTest(("three-of-a-kind", new[] { "Q", "K", "J" }), new[] { "Q♣", "Q♦" }, new[] { "K♠", "Q♥", "9♥", "2♥", "J♦" });
- 113
- 114 // board straight cancels out pocket aces
- 115 SampleTest(("straight", new[] { "A", "K", "Q", "J", "10" }), new[] { "A♥", "A♠" }, new[] { "A♣", "K♥", "Q♥", "J♥", "10♦" });
- 116 // super straight
- 117 SampleTest(("straight", new[] { "A", "K", "Q", "J", "10" }), new[] { "A♠", "Q♥" }, new[] { "K♥", "10♠", "J♠", "9♠", "8♦" });
- 118 // high straight
- 119 SampleTest(("straight", new[] { "7", "6", "5", "4", "3" }), new[] { "6♠", "7♥" }, new[] { "3♥", "4♠", "5♠", "10♠", "10♦" });
- 120 // low straight
- 121 SampleTest(("straight", new[] { "6", "5", "4", "3", "2" }), new[] { "2♠", "3♥" }, new[] { "4♥", "5♠", "6♠", "10♠", "10♦" });
- 122 // outside straight
- 123 SampleTest(("straight", new[] { "6", "5", "4", "3", "2" }), new[] { "2♠", "6♥" }, new[] { "4♥", "5♠", "3♠", "10♠", "10♦" });
- 124 // inside straight
- 125 SampleTest(("straight", new[] { "6", "5", "4", "3", "2" }), new[] { "4♠", "3♥" }, new[] { "2♥", "5♠", "6♠", "10♠", "10♦" });
- 126 // interspersed straight
- 127 SampleTest(("straight", new[] { "6", "5", "4", "3", "2" }), new[] { "4♠", "2♥" }, new[] { "3♥", "5♠", "6♠", "10♠", "10♦" });
- 128
- 129 // seven deuce runner runner
- 130 SampleTest(("full house", new[] { "2", "7" }), new[] { "7♥", "2♠" }, new[] { "A♣", "K♥", "2♦", "7♣", "2♥" });
- 131 // full house with 2 pairs on board where pockets make the triple
- 132 SampleTest(("full house", new[] { "A", "K" }), new[] { "A♠", "A♦" }, new[] { "K♣", "K♥", "A♥", "Q♥", "Q♦" });
- 133 // full house with 1 pair on board where pockets make the triple
- 134 SampleTest(("full house", new[] { "A", "K" }), new[] { "A♠", "A♦" }, new[] { "K♣", "K♥", "A♥", "J♥", "Q♦" });
- 135 // full house with 1 hole card making triple and other making pair
- 136 SampleTest(("full house", new[] { "K", "A" }), new[] { "A♠", "K♦" }, new[] { "K♣", "K♥", "A♥", "J♥", "Q♦" });
- 137 // full house with better triple than board
- 138 SampleTest(("full house", new[] { "A", "K" }), new[] { "A♠", "A♦" }, new[] { "K♣", "K♥", "A♥", "Q♥", "K♦" });
- 139
- 140 // flush and straight combo
- 141 SampleTest(("flush", new[] { "J", "10", "9", "8", "6" }), new[] { "8♠", "6♠" }, new[] { "7♦", "5♠", "9♠", "J♠", "10♠" });
- 142 // power flush
- 143 SampleTest(("flush", new[] { "A", "K", "Q", "J", "9" }), new[] { "A♠", "Q♠" }, new[] { "K♠", "4♠", "J♠", "9♠", "3♠" });
- 144
- 145 // four-of-a-kind on board
- 146 SampleTest(("four-of-a-kind", new[] { "A", "K" }), new[] { "K♠", "9♥" }, new[] { "A♥", "A♣", "A♠", "A♦", "3♥" });
- 147 // four-of-a-kind with 1 hole card and triple on board
- 148 SampleTest(("four-of-a-kind", new[] { "A", "K" }), new[] { "K♠", "A♥" }, new[] { "9♥", "A♣", "A♠", "A♦", "3♥" });
- 149 // carré
- 150 SampleTest(("four-of-a-kind", new[] { "A", "K" }), new[] { "A♠", "A♦" }, new[] { "A♥", "A♣", "K♠", "9♥", "3♥" });
- 151
- 152 // royal flush
- 153 SampleTest(("straight-flush", new[] { "A", "K", "Q", "J", "10" }), new[] { "A♠", "Q♠" }, new[] { "K♠", "10♠", "J♠", "9♠", "3♦" });
- 154
- 155 // regression tests
- 156 SampleTest(("straight", new[] { "6", "5", "4", "3", "2" }), new[] { "3♠", "4♥" }, new[] { "6♣", "5♠", "2♣", "2♦", "3♦" });
- 157 SampleTest(("straight", new[] { "10", "9", "8", "7", "6" }), new[] { "6♣", "10♠" }, new[] { "9♠", "8♦", "5♦", "7♥", "9♦" });
- 158 SampleTest(("straight", new[] { "K", "Q", "J", "10", "9" }), new[] { "2♦", "J♦" }, new[] { "Q♥", "9♠", "K♥", "10♥", "J♥" });
- 159 }
- 160
- 161 [Test(Description = "Random Tests (Batch #1)")]
- 162 public void RandomBatch1Tests()
- 163 {
- 164 var rand = new Random((int)(DateTime.Now.Ticks % int.MaxValue));
- 165 var bulkSize = 500;
- 166 for (var i = 0; i < bulkSize; i++)
- 167 {
- 168 var hand = GenerateRandomHand(rand);
- 169 var holeCards = hand.Take(2).ToArray();
- 170 var communityCards = hand.Skip(2).ToArray();
- 171 Test(holeCards, communityCards);
- 172 }
- 173 }
- 174
- 175 [Test(Description = "Random Tests (Batch #2)")]
- 176 public void RandomBatch2Tests()
- 177 {
- 178 var rand = new Random((int)(DateTime.Now.Ticks % int.MaxValue));
- 179 var bulkSize = 500;
- 180 for (var i = 0; i < bulkSize; i++)
- 181 {
- 182 do
- 183 {
- 184 var hand = GenerateRandomHand(rand);
- 185 var holeCards = hand.Take(2).ToArray();
- 186 var communityCards = hand.Skip(2).ToArray();
- 187 var expected = Expect(holeCards, communityCards);
- 188
- 189 if (new[] { "nothing", "pair", "two pair", "three-of-a-kind" }.Contains(expected.type))
- 190 {
- 191 continue;
- 192 }
- 193 else
- 194 {
- 195 Test(holeCards, communityCards);
- 196 break;
- 197 }
- 198 } while (true);
- 199 }
- 200 }
- 201
- 202 [Test(Description = "Random Tests (Batch #3)")]
- 203 public void RandomBatch3Tests()
- 204 {
- 205 var rand = new Random((int)(DateTime.Now.Ticks % int.MaxValue));
- 206 var hands = new List<string[]>();
- 207 var batchSize = 100;
- 208 for (var i = 0; i < batchSize; i++) hands.Add(GenerateStraightFlush(rand));
- 209 for (var i = 0; i < batchSize; i++) hands.Add(GenerateFourOfAKind(rand));
- 210 for (var i = 0; i < batchSize; i++) hands.Add(GenerateFullHouse(rand));
- 211 for (var i = 0; i < batchSize; i++) hands.Add(GenerateFlush(rand));
- 212 for (var i = 0; i < batchSize; i++) hands.Add(GenerateStraight(rand));
- 213 hands = hands.Select(x => x.OrderBy(y => rand.Next()).ToArray()).OrderBy(x => rand.Next()).ToList();
- 214 foreach (var hand in hands)
- 215 {
- 216 var holeCards = hand.Take(2).ToArray();
- 217 var communityCards = hand.Skip(2).ToArray();
- 218 Test(holeCards, communityCards);
- 219 }
- 220 }
- 221
- 222 private static Dictionary<int, (string rank, string suit, int id)> Deck()
- 223 {
- 224 var id = 0;
- 225 var hand = new List<string>();
- 226 return (from suit in suits
- 227 from rank in ranks
- 228 select (rank, suit, id: id++)).ToDictionary(x => x.id);
- 229 }
- 230
- 231 private static void RemoveSuit(Dictionary<int, (string rank, string suit, int id)> deck, int suit)
- 232 {
- 233 var list = deck.Values.Where(card => card.id / ranks.Length == suit).ToList();
- 234 foreach (var card in list)
- 235 {
- 236 deck.Remove(card.id);
- 237 }
- 238 }
- 239
- 240 private static void RemoveRank(Dictionary<int, (string rank, string suit, int id)> deck, int rank)
- 241 {
- 242 var list = deck.Values.Where(card => card.id % ranks.Length == rank).ToList();
- 243 foreach (var card in list)
- 244 {
- 245 deck.Remove(card.id);
- 246 }
- 247 }
- 248
- 249 private static (string rank, string suit, int id) RandomCard(Dictionary<int, (string rank, string suit, int id)> deck, Random rand)
- 250 {
- 251 return deck.Skip(rand.Next(0, deck.Count)).First().Value;
- 252 }
- 253
- 254 private static string[] GenerateRandomHand(Random rand)
- 255 {
- 256 var hand = new List<string>();
- 257 var deck = Deck();
- 258
- 259 while (hand.Count < 7)
- 260 {
- 261 var next = RandomCard(deck, rand);
- 262 deck.Remove(next.id);
- 263 hand.Add($"{next.rank}{next.suit}");
- 264 }
- 265
- 266 return hand.ToArray();
- 267 }
- 268
- 269 private static string[] GenerateStraightFlush(Random rand)
- 270 {
- 271 var hand = new List<string>();
- 272 var deck = Deck();
- 273 var suit = rand.Next(0, suits.Length);
- 274 var rank = rand.Next(0, ranks.Length - 5);
- 275 var head = suit * ranks.Length + rank;
- 276 // 5 cards make the straight flush
- 277 for (var i = 0; i < 5; i++)
- 278 {
- 279 var current = head + i;
- 280 var card = deck[current];
- 281 deck.Remove(current);
- 282 hand.Add($"{card.rank}{card.suit}");
- 283 }
- 284 // any 2 other cards may be added
- 285 for (var i = 0; i < 2; i++)
- 286 {
- 287 var card = RandomCard(deck, rand);
- 288 deck.Remove(card.id);
- 289 hand.Add($"{card.rank}{card.suit}");
- 290 }
- 291 return hand.ToArray();
- 292 }
- 293
- 294 private static string[] GenerateFourOfAKind(Random rand)
- 295 {
- 296 var hand = new List<string>();
- 297 var deck = Deck();
- 298 var rank = rand.Next(0, ranks.Length);
- 299 var head = rank;
- 300 // 4 cards make the four-of-a-kind
- 301 for (var i = 0; i < 4; i++)
- 302 {
- 303 var current = head + i * ranks.Length;
- 304 var card = deck[current];
- 305 deck.Remove(current);
- 306 hand.Add($"{card.rank}{card.suit}");
- 307 }
- 308 // any 3 other cards may be added
- 309 for (var i = 0; i < 3; i++)
- 310 {
- 311 var card = RandomCard(deck, rand);
- 312 deck.Remove(card.id);
- 313 hand.Add($"{card.rank}{card.suit}");
- 314 }
- 315 return hand.ToArray();
- 316 }
- 317
- 318 private static string[] GenerateFullHouse(Random rand)
- 319 {
- 320 var hand = new List<string>();
- 321 var deck = Deck();
- 322 var rank = rand.Next(0, ranks.Length);
- 323 var head = rank;
- 324 // 3 cards make the triple
- 325 for (var i = 0; i < 3; i++)
- 326 {
- 327 var current = head + i * ranks.Length;
- 328 var card = deck[current];
- 329 deck.Remove(current);
- 330 hand.Add($"{card.rank}{card.suit}");
- 331 }
- 332 // remaining rank would result in a four-of-a-kind
- 333 RemoveRank(deck, rank);
- 334 // 2 cards make a pair
- 335 var rank2 = Array.IndexOf(ranks, RandomCard(deck, rand).rank);
- 336 var head2 = rank2;
- 337 for (var i = 0; i < 2; i++)
- 338 {
- 339 var current = head2 + i * ranks.Length;
- 340 var card = deck[current];
- 341 deck.Remove(current);
- 342 hand.Add($"{card.rank}{card.suit}");
- 343 }
- 344 // remaining rank would result in a three-of-a-kind
- 345 RemoveRank(deck, rank2);
- 346 // any 2 other cards may be added
- 347 for (var i = 0; i < 2; i++)
- 348 {
- 349 var card = RandomCard(deck, rand);
- 350 deck.Remove(card.id);
- 351 hand.Add($"{card.rank}{card.suit}");
- 352 }
- 353 return hand.ToArray();
- 354 }
- 355
- 356 private static string[] GenerateFlush(Random rand)
- 357 {
- 358 var hand = new List<string>();
- 359 var deck = Deck();
- 360 var primaryDeck = Deck();
- 361 var suit = rand.Next(0, suits.Length);
- 362 for (var i = 0; i < 4; i++)
- 363 {
- 364 if (i != suit) RemoveSuit(primaryDeck, i);
- 365 }
- 366 // 5 cards make a flush
- 367 for (var i = 0; i < 5; i++)
- 368 {
- 369 var card = RandomCard(primaryDeck, rand);
- 370 primaryDeck.Remove(card.id);
- 371 deck.Remove(card.id);
- 372 hand.Add($"{card.rank}{card.suit}");
- 373 }
- 374 // any 2 other cards may be added
- 375 // small chance on straight flush, but that's ok
- 376 for (var i = 0; i < 2; i++)
- 377 {
- 378 var card = RandomCard(deck, rand);
- 379 deck.Remove(card.id);
- 380 hand.Add($"{card.rank}{card.suit}");
- 381 }
- 382 return hand.ToArray();
- 383 }
- 384
- 385 private static string[] GenerateStraight(Random rand)
- 386 {
- 387 var hand = new List<string>();
- 388 var deck = Deck();
- 389 var rank = rand.Next(0, ranks.Length - 5);
- 390 var head = rank;
- 391 // 5 cards make the straight
- 392 for (var i = 0; i < 5; i++)
- 393 {
- 394 var suit = rand.Next(0, suits.Length);
- 395 var current = head + i + suit * ranks.Length;
- 396 var card = deck[current];
- 397 deck.Remove(current);
- 398 hand.Add($"{card.rank}{card.suit}");
- 399 }
- 400 // any 2 other cards may be added
- 401 // small chance on straight flush, but that's ok
- 402 for (var i = 0; i < 2; i++)
- 403 {
- 404 var card = RandomCard(deck, rand);
- 405 deck.Remove(card.id);
- 406 hand.Add($"{card.rank}{card.suit}");
- 407 }
- 408 return hand.ToArray();
- 409 }
- 410
- 411 private static void Test(string[] holeCards, string[] communityCards)
- 412 {
- 413 var expected = Expect(holeCards, communityCards);
- 414 var actual = Act(holeCards, communityCards);
- 415 Verify(expected, actual, holeCards, communityCards);
- 416 if (!stats.TryGetValue(expected.type, out var cnt)) cnt = 0;
- 417 stats[expected.type] = cnt + 1;
- 418 }
- 419
- 420 private static (string type, string[] ranks) Expect(string[] holeCards, string[] communityCards)
- 421 {
- 422 var cards = holeCards.Concat(communityCards).Select(Parse).OrderBy(x => ranksLookup[x.rank]).ToArray();
- 423 var cardsByRank = cards.ToLookup(x => x.rank);
- 424 var cardsBySuit = cards.ToLookup(x => x.suit);
- 425 var ans = findStraightFlush();
- 426 if (ans == null) ans = findFourOfAKind();
- 427 if (ans == null) ans = findFullHouse();
- 428 if (ans == null) ans = findFlush();
- 429 if (ans == null) ans = findStraight();
- 430 if (ans == null) ans = findThreeOfAKind();
- 431 if (ans == null) ans = findTwoPair();
- 432 if (ans == null) ans = findPair();
- 433 if (ans == null) ans = findNothing();
- 434 return ans.GetValueOrDefault(default);
- 435
- 436 (string rank, string suit) Parse(string card) => (card.Substring(0, card.Length - 1), card.Substring(card.Length - 1, 1));
- 437
- 438 (string type, string[] ranks)? findStraightFlush()
- 439 {
- 440 var flush = cardsBySuit.SingleOrDefault(x => x.Count() >= 5)?.ToArray();
- 441 if (flush == null) return null;
- 442 for (var i = 0; i + 4 < flush.Length; i++)
- 443 {
- 444 var match = true;
- 445 for (var j = 1; j <= 4; j++)
- 446 {
- 447 if (!flush.Any(card => ranksLookup[card.rank] == ranksLookup[flush[i].rank] + j))
- 448 {
- 449 match = false;
- 450 break;
- 451 }
- 452 }
- 453 if (match) return ("straight-flush", Enumerable.Range(0, 5).Select(k => ranks[k + ranksLookup[flush[i].rank]]).ToArray());
- 454 }
- 455 return null;
- 456 }
- 457
- 458 (string type, string[] ranks)? findFourOfAKind()
- 459 {
- 460 var t4_cards = cardsByRank.SingleOrDefault(x => x.Count() == 4);
- 461 if (t4_cards == null) return null;
- 462 var t4 = t4_cards.First().rank;
- 463 var h1 = cardsByRank.First(x => x.Key != t4).Key;
- 464 return ("four-of-a-kind", new[] { t4, h1 });
- 465 }
- 466
- 467 (string type, string[] ranks)? findFullHouse()
- 468 {
- 469 var t3_set = cardsByRank.Where(x => x.Count() == 3);
- 470 if (!t3_set.Any()) return null;
- 471 var t3 = t3_set.First().First().rank;
- 472 var t2_ranks = cardsByRank.Where(x => x.Count() == 2).Select(x => x.Key).ToList();
- 473 if (t3_set.Count() > 1) t2_ranks.Add(t3_set.Skip(1).First().Key);
- 474 if (!t2_ranks.Any()) return null;
- 475 var t2 = t2_ranks.OrderBy(x => ranksLookup[x]).First();
- 476 return ("full house", new[] { t3, t2 });
- 477 }
- 478
- 479 (string type, string[] ranks)? findFlush()
- 480 {
- 481 var flush = cardsBySuit.SingleOrDefault(x => x.Count() >= 5)?.ToArray();
- 482 if (flush == null) return null;
- 483 return ("flush", flush.Take(5).Select(x => x.rank).ToArray());
- 484 }
- 485
- 486 (string type, string[] ranks)? findStraight()
- 487 {
- 488 for (var i = 0; i + 4 < cards.Length; i++)
- 489 {
- 490 var match = true;
- 491 for (var j = 1; j <= 4; j++)
- 492 {
- 493 if (!cards.Any(card => ranksLookup[card.rank] == ranksLookup[cards[i].rank] + j))
- 494 {
- 495 match = false;
- 496 break;
- 497 }
- 498 }
- 499 if (match) return ("straight", Enumerable.Range(0, 5).Select(k => ranks[k + ranksLookup[cards[i].rank]]).ToArray());
- 500 }
- 501 return null;
- 502 }
- 503
- 504 (string type, string[] ranks)? findThreeOfAKind()
- 505 {
- 506 var t3_cards = cardsByRank.SingleOrDefault(x => x.Count() == 3);
- 507 if (t3_cards == null) return null;
- 508 var t3 = t3_cards.First().rank;
- 509 var h1 = cardsByRank.First(x => x.Key != t3).Key;
- 510 var h2 = cardsByRank.First(x => x.Key != t3 && x.Key != h1).Key;
- 511 return ("three-of-a-kind", new[] { t3, h1, h2 });
- 512 }
- 513
- 514 (string type, string[] ranks)? findTwoPair()
- 515 {
- 516 var t2_set = cardsByRank.Where(x => x.Count() == 2);
- 517 if (t2_set.Count() < 2) return null;
- 518 var t2_high = t2_set.First().First().rank;
- 519 var t2_low = t2_set.Skip(1).First().First().rank;
- 520 var h1 = cardsByRank.First(x => x.Key != t2_high && x.Key != t2_low).Key;
- 521 return ("two pair", new[] { t2_high, t2_low, h1 });
- 522 }
- 523
- 524 (string type, string[] ranks)? findPair()
- 525 {
- 526 var t2_cards = cardsByRank.SingleOrDefault(x => x.Count() == 2);
- 527 if (t2_cards == null) return null;
- 528 var t2 = t2_cards.First().rank;
- 529 var h1 = cardsByRank.First(x => x.Key != t2).Key;
- 530 var h2 = cardsByRank.First(x => x.Key != t2 && x.Key != h1).Key;
- 531 var h3 = cardsByRank.First(x => x.Key != t2 && x.Key != h1 && x.Key != h2).Key;
- 532 return ("pair", new[] { t2, h1, h2, h3 });
- 533 }
- 534
- 535 (string type, string[] ranks) findNothing()
- 536 {
- 537 return ("nothing", cards.Take(5).Select(x => x.rank).ToArray());
- 538 }
- 539 }
- 540
- 541 #endregion
- 542 }
- 543 }
复制代码
来源:https://www.cnblogs.com/lan80/archive/2023/08/07/17610735.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作! |
|