清风一缕入梦来 发表于 2023-8-7 11:49:37

【算法】用c#实现德州扑克卡牌游戏规则

德州扑克是一种牌类游戏,可多人参与,它的玩法是,玩家每人发两张底牌,桌面依次发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 }; //"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.value - cards.value == 1)
99                     {
100                         rtnList.Add(cards);
101
102                         if (rtnList.Count() == 5)
103                         {
104                           return ("straight", rtnList.ToArray());
105                         }
106                         counter--;
107                         j++;
108                     }
109                     else if (cards.value - cards.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 == '1')? "10": Char.ToString(s);
203             value = mapping.ContainsKey(s)? mapping]: (int) Char.GetNumericValue(s);
204             suit = s;
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   
11   public class SolutionTest
12   {
13         #region Sample Tests
14   
15         
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)),
71                     Error($"{Show(actual.ranks)} is not valid, valid options are: {ShowSeq(ranks)}"));
72             for (var i = 0; i < expected.ranks.Length; i++)
73               Assert.AreEqual(expected.ranks, actual.ranks, 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         
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         
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         
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         
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;
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;
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;
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;
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;
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 = 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).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 == ranksLookup.rank] + j))
448                         {
449                           match = false;
450                           break;
451                         }
452                     }
453                     if (match) return ("straight-flush", Enumerable.Range(0, 5).Select(k => ranks.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).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 == ranksLookup.rank] + j))
494                         {
495                           match = false;
496                           break;
497                         }
498                     }
499                     if (match) return ("straight", Enumerable.Range(0, 5).Select(k => ranks.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】 我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: 【算法】用c#实现德州扑克卡牌游戏规则