德州扑克是一种牌类游戏,可多人参与,它的玩法是,玩家每人发两张底牌,桌面依次发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 }

【算法】用c#实现德州扑克卡牌游戏规则的更多相关文章

  1. [JZOJ4684] 【GDOI2017模拟8.11】卡牌游戏

    题目 描述 题目大意 有111到2n2n2n牌,一开始分别给两个人,每人nnn张. 轮流出牌,给出对手出牌的顺序,若自己的牌更大,就记一分. 在中间的某个时刻可以改变游戏规则. 问最大的分数. 思考历 ...

  2. 使用UIKit制作卡牌游戏(三)ios游戏篇

    译者: Lao Jiang | 原文作者: Matthijs Hollemans写于2012/07/13 转自朋友Tommy 的翻译,自己只翻译了这第三篇教程. 原文地址: http://www.ra ...

  3. [Firefly引擎][学习笔记二][已完结]卡牌游戏开发模型的设计

    源地址:http://bbs.9miao.com/thread-44603-1-1.html 在此补充一下Socket的验证机制:socket登陆验证.会采用session会话超时的机制做心跳接口验证 ...

  4. BZOJ_3191_[JLOI2013]卡牌游戏_概率DP

    BZOJ_3191_[JLOI2013]卡牌游戏_概率DP Description   N个人坐成一圈玩游戏.一开始我们把所有玩家按顺时针从1到N编号.首先第一回合是玩家1作为庄家.每个回合庄家都会随 ...

  5. 洛谷 P2059 [JLOI2013]卡牌游戏 解题报告

    P2059 [JLOI2013]卡牌游戏 题意 有\(n\)个人玩约瑟夫游戏,有\(m\)张卡,每张卡上有一个正整数,每次庄家有放回的抽一张卡,干掉从庄家起顺时针的第\(k\)个人(计算庄家),干掉的 ...

  6. bzoj千题计划202:bzoj3191: [JLOI2013]卡牌游戏

    http://www.lydsy.com/JudgeOnline/problem.php?id=3191 每个人获胜的概率只与其在排列中与庄家的相对位置有关 dp[i][j] 还剩i个人时,从庄家数第 ...

  7. nowcoder 202H-卡牌游戏

    题目链接 题目描述 小贝喜欢玩卡牌游戏.某个游戏体系中共有N种卡牌,其中M种是稀有的.小贝每次和电脑对决获胜之后都会有一个抽卡机会,这时系统会随机从N种卡中选择一张给小贝.普通卡可能多次出现,而稀有卡 ...

  8. 【BZOJ3191】【JLOI2013】卡牌游戏 [DP]

    卡牌游戏 Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description   N个人坐成一圈玩游戏.一开始我 ...

  9. TCG卡牌游戏研究:《炉石战记:魔兽英雄传》所做的改变

    转自:http://www.gameres.com/665306.html TCG演进史 说到卡牌游戏,大家会联想到什么呢? 是历史悠久的扑克牌.风靡全球的<MTG 魔法风云会>与< ...

  10. BZOJ 4392 卡牌游戏

    Description 奶牛贝茜是卡牌游戏的狂热爱好者, 但是令人吃惊的, 她缺乏对手. 不幸的是, 任何牧 群里的其他牛都不是好对手. 他们实在是太差了 , 实际上, 他们玩卡牌游戏时会遵循一种完全 ...

随机推荐

  1. 【Linux】sed文本处理及软件管理

    软件管理 1.编译安装http2.4,实现可以正常访问 安装编译相关工具包 root@mirror-centos8-p11 ~]# yum install gcc make autoconf apr- ...

  2. 【易车网实例】x-sign逆向保姆级教程

    易车号x-sign逆向 前言 许多网站都有反爬机制,x-sign加密就是许多反爬虫机制的其中一种,本次将以易车号作为目标进行演示. 方法仅供学习参考. 链接:https://hao.yiche.com ...

  3. 一种KV存储的GC优化实践

    作者:vivo 互联网服务器团队- Yuan Jian Wei 从内部需求出发,我们基于TiKV设计了一款兼容Redis的KV存储.基于TiKV的数据存储机制,对于窗口数据的处理以及过期数据的GC问题 ...

  4. Git&GitHub简介与入手(一)

    一.Git版本控制 1.集中式版本控制工具:SVN(版本控制集中在服务器端,会有单点故障风险): 2.分布式版本控制工具:Git: 3.Git简史 Talk is cheap, show me the ...

  5. 音视频八股文(6)-- ffmpeg大体介绍和内存模型

    播放器框架 常用音视频术语 • 容器/文件(Conainer/File):即特定格式的多媒体文件, 比如mp4.flv.mkv等. • 媒体流(Stream):表示时间轴上的一段连续数据,如一 段声音 ...

  6. 2022-11-03:给定一个数组arr,和一个正数k 如果arr[i] == 0,表示i这里既可以是左括号也可以是右括号, 而且可以涂上1~k每一种颜色 如果arr[i] != 0,表示i这里已经确

    2022-11-03:给定一个数组arr,和一个正数k 如果arr[i] == 0,表示i这里既可以是左括号也可以是右括号, 而且可以涂上1~k每一种颜色 如果arr[i] != 0,表示i这里已经确 ...

  7. vue全家桶进阶之路1:前言

    Vue.js简称Vue,用于构建用户界面的渐进式框架. Vue是一款国产前端框架,它的作者尤雨溪(Evan You)是一位美籍华人,2014年2月,尤雨溪开源了一个前端开发库 Vue.js,2015年 ...

  8. 2023-05-23:如果交换字符串 X 中的两个不同位置的字母,使得它和字符串 Y 相等, 那么称 X 和 Y 两个字符串相似。如果这两个字符串本身是相等的,那它们也是相似的。 例如,“tars“

    2023-05-23:如果交换字符串 X 中的两个不同位置的字母,使得它和字符串 Y 相等, 那么称 X 和 Y 两个字符串相似.如果这两个字符串本身是相等的,那它们也是相似的. 例如,"t ...

  9. SpringMVC 后台从前端获取单个参数

    1.编写web.xml(模板) 2.springmvc配置文件 3.编写对应数据库字段的pojo实体类 @Data @AllArgsConstructor @NoArgsConstructor pub ...

  10. rest framework 学习 序列化

    序列化功能:对请求数据进行验证和对Queryset进行序列化     Queryset进行序列化:         1  序列化之Serializer 1 class UserInfoSerializ ...