Last active
July 28, 2019 10:38
-
-
Save evgeniyp/19f22bf9eecd46d8868500550d5feb09 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
public enum Suit { Spades = '♠', Clubs = '♣', Diamonds = '♦', Hearts = '♥' } | |
public enum Rank { Two = '2', Three = '3', Four = '4', Five = '5', Six = '6', Seven = '7', Eight = '8', Nine = '9', Ten = 'T', Jack = 'J', Queen = 'Q', King = 'K', Ace = 'A' } | |
public class Card { | |
public static Card Parse(string rankSuit) { | |
if (rankSuit.Length != 2) { | |
throw new Exception($"Unusual rankSuit: '{rankSuit}'"); | |
} | |
return new Card(rankSuit[0], rankSuit[1]); | |
} | |
public static IEnumerable<Card> ParseMany(string commaSeparatedString) { | |
return commaSeparatedString.Split(',').Select(s => Card.Parse(s)); | |
} | |
public Rank Rank; | |
public Suit Suit; | |
public Card(Rank rank, Suit suit) { | |
if (!Enum.IsDefined(typeof(Rank), rank) || !Enum.IsDefined(typeof(Suit), suit)) { | |
throw new Exception($"Unusual rank:'{rank}' or suit:'{suit}'"); | |
} | |
this.Rank = rank; | |
this.Suit = suit; | |
} | |
public Card(Char rank, Char suit) : this((Rank)rank, (Suit)suit) { } | |
public override string ToString() => $"{(Char)this.Rank}{(Char)this.Suit}"; | |
#region Overrided equality | |
public override bool Equals(object otherCard) { | |
if (otherCard == null || this.GetType() != otherCard.GetType()) { | |
return false; | |
} else { | |
return Rank == ((Card)otherCard).Rank && Suit == ((Card)otherCard).Suit; | |
} | |
} | |
public override int GetHashCode() => 1000 * (int)Rank + (int)Suit; | |
#endregion | |
} | |
public class RankComparer : IComparer<Rank> { | |
private static Dictionary<Rank, int> Weights = new Dictionary<Rank, int>() { {Rank.Two, 2}, {Rank.Three, 3}, {Rank.Four, 4}, {Rank.Five, 5}, {Rank.Six, 6}, {Rank.Seven, 7}, {Rank.Eight, 8}, {Rank.Nine, 9}, {Rank.Ten, 10}, {Rank.Jack, 11}, {Rank.Queen, 12}, {Rank.King, 13}, {Rank.Ace, 14} }; | |
public static int CompareStatic(Rank x, Rank y) { | |
int weightX = Weights.ContainsKey(x) ? Weights[x] : (int)x; | |
int weightY = Weights.ContainsKey(y) ? Weights[y] : (int)y; | |
return weightX == weightY ? 0 : weightX < weightY ? -1 : 1; | |
} | |
public static int CompareStatic(Card x, Card y) => CompareStatic(x.Rank, y.Rank); | |
public int Compare(Rank x, Rank y) => CompareStatic(x, y); | |
} | |
public static class CardUtils { | |
private static RankComparer comparer = new RankComparer(); | |
public static IEnumerable<Card> OrderByRank(this IEnumerable<Card> cards) { | |
return cards.OrderBy(o => o.Rank, comparer); | |
} | |
} | |
public enum CombinationName { HighCard = 0, OnePair, TwoPairs, ThreeOfAKind, Straight, Flush, FullHouse, FourOfAKind, StraightFlush } | |
public class Combination { | |
private static readonly Rank[][] StraightRanks = new Rank[][] | |
{ | |
new Rank[] { Rank.Ten, Rank.Jack, Rank.Queen, Rank.King, Rank.Ace }, | |
new Rank[] {Rank.Nine, Rank.Ten, Rank.Jack, Rank.Queen, Rank.King}, | |
new Rank[] {Rank.Eight, Rank.Nine, Rank.Ten, Rank.Jack, Rank.Queen}, | |
new Rank[] {Rank.Seven, Rank.Eight, Rank.Nine, Rank.Ten, Rank.Jack}, | |
new Rank[] {Rank.Six, Rank.Seven, Rank.Eight, Rank.Nine, Rank.Ten}, | |
new Rank[] {Rank.Five, Rank.Six, Rank.Seven, Rank.Eight, Rank.Nine}, | |
new Rank[] {Rank.Four, Rank.Five, Rank.Six, Rank.Seven, Rank.Eight}, | |
new Rank[] {Rank.Three, Rank.Four, Rank.Five, Rank.Six, Rank.Seven}, | |
new Rank[] {Rank.Two, Rank.Three, Rank.Four, Rank.Five, Rank.Six}, | |
new Rank[] {Rank.Ace, Rank.Two, Rank.Three, Rank.Four, Rank.Five}, | |
}; | |
public static (CombinationName, IEnumerable<Card> cards, IEnumerable<Card> kickers) GetBest(IEnumerable<Card> hand) { | |
if (hand.Count() != 7) { | |
throw new Exception("Seven cards needed"); | |
} | |
{ // StraightFlush | |
var suitedN = hand.GroupBy(g => g.Suit).FirstOrDefault(w => w.Count() >= 5); | |
if (suitedN != null) { | |
var suit = suitedN.First().Suit; | |
var ranks = suitedN.Select(s => s.Rank); | |
var matchedRank = StraightRanks.FirstOrDefault(straightRank => straightRank.All(rank => ranks.Contains(rank))); | |
if (matchedRank != null) { | |
var cards = matchedRank.Select(rank => new Card(rank, suit)); | |
return (CombinationName.StraightFlush, cards, Enumerable.Empty<Card>()); | |
} | |
} | |
} | |
{ // FourOfAKind | |
var sameRanks = hand.GroupBy(g => g.Rank).Where(w => w.Count() == 4).FirstOrDefault(); | |
if (sameRanks != null) { | |
var kickers = hand.Except(sameRanks).OrderByRank().Last(); | |
return (CombinationName.FourOfAKind, sameRanks, Enumerable.Repeat<Card>(kickers, 1)); | |
} | |
} | |
{ // FullHouse | |
var bestTriple = hand.GroupBy(g => g.Rank).Where(w => w.Count() == 3) | |
.OrderBy(o => o.First(), Comparer<Card>.Create(RankComparer.CompareStatic)).LastOrDefault(); | |
if (bestTriple != null) { | |
var otherCards = hand.Except(bestTriple); | |
var bestTuple = otherCards.GroupBy(g => g.Rank).Where(w => w.Count() >= 2) | |
.OrderBy(o => o.First(), Comparer<Card>.Create(RankComparer.CompareStatic)).LastOrDefault(); | |
if (bestTuple != null) { | |
var sureTuple = bestTriple.TakeLast(2); | |
return (CombinationName.FullHouse, bestTriple.Concat(sureTuple), Enumerable.Empty<Card>()); | |
} | |
} | |
} | |
{ // Flush | |
var flushCandidate = hand.GroupBy(g => g.Suit).FirstOrDefault(f => f.Count() >= 5); | |
if (flushCandidate != null) { | |
return (CombinationName.Flush, flushCandidate.OrderByRank().TakeLast(5), Enumerable.Empty<Card>()); | |
} | |
} | |
{ // Straight | |
var ranks = hand.Select(s => s.Rank); | |
var matchedRank = StraightRanks.FirstOrDefault(straightRank => straightRank.All(rank => ranks.Contains(rank))); | |
if (matchedRank != null) { | |
var cards = matchedRank.Select(rank => hand.First(f => f.Rank == rank)); | |
return (CombinationName.Straight, cards, Enumerable.Empty<Card>()); | |
} | |
} | |
{ // ThreeOfAKind | |
var triple = hand.GroupBy(g => g.Rank).FirstOrDefault(w => w.Count() == 3); | |
if (triple != null) { | |
var kickers = hand.Except(triple).OrderByRank().TakeLast(2); | |
return (CombinationName.ThreeOfAKind, triple, kickers); | |
} | |
} | |
{ // TwoPairs | |
var bestPairs = hand.GroupBy(g => g.Rank).Where(w => w.Count() == 2) | |
.OrderBy(o => o.First(), Comparer<Card>.Create(RankComparer.CompareStatic)).TakeLast(2); | |
if (bestPairs.Count() == 2) { | |
var bestPairsFlat = bestPairs.First().Concat(bestPairs.Last()); | |
var kickers = hand.Except(bestPairsFlat).OrderByRank().Last(); | |
return (CombinationName.TwoPairs, bestPairsFlat, Enumerable.Repeat(kickers, 1)); | |
} | |
} | |
{ // OnePair | |
var bestPair = hand.GroupBy(g => g.Rank).Where(w => w.Count() == 2) | |
.OrderBy(o => o.First(), Comparer<Card>.Create(RankComparer.CompareStatic)).LastOrDefault(); | |
if (bestPair != null) { | |
var kickers = hand.Except(bestPair).OrderByRank().TakeLast(3); | |
return (CombinationName.OnePair, bestPair, kickers); | |
} | |
} | |
{ // HighCard | |
var orderedCards = hand.OrderByRank(); | |
var cards = orderedCards.TakeLast(1); | |
var kickers = orderedCards.Skip(2).Take(4); | |
return (CombinationName.HighCard, cards, kickers); | |
} | |
} | |
} | |
class Program { | |
static void Main(string[] args) { | |
var allCardsList = new List<Card>(); | |
foreach (Suit suit in Enum.GetValues(typeof(Suit))) { | |
foreach (Rank rank in Enum.GetValues(typeof(Rank))) { | |
allCardsList.Add(new Card(rank, suit)); | |
} | |
} | |
var allCards = allCardsList.ToArray(); | |
var dictionary = new Dictionary<CombinationName, int>(); | |
foreach (CombinationName combination in Enum.GetValues(typeof(CombinationName))) { | |
dictionary[combination] = 0; | |
} | |
int counter = 0; | |
var startTime = DateTime.Now; | |
for (var i1 = 0; i1 < 46; i1++) | |
for (var i2 = i1 + 1; i2 < 47; i2++) | |
for (var i3 = i2 + 1; i3 < 48; i3++) | |
for (var i4 = i3 + 1; i4 < 49; i4++) | |
for (var i5 = i4 + 1; i5 < 50; i5++) | |
for (var i6 = i5 + 1; i6 < 51; i6++) | |
for (var i7 = i6 + 1; i7 < 52; i7++) { | |
counter++; | |
var hand = new List<Card>() { allCards[i1], allCards[i2], allCards[i3], allCards[i4], allCards[i5], allCards[i6], allCards[i7] }; | |
var (name, cards, kickers) = Combination.GetBest(hand); | |
dictionary[name] += 1; | |
if (counter % 1000000 == 0) { | |
Console.WriteLine($"{counter} combinations: {string.Join(";", dictionary.Select(x => x.Key + "=" + x.Value).ToArray())}"); | |
} | |
} | |
Console.WriteLine($"{counter} combinations: {string.Join(";", dictionary.Select(x => x.Key + "=" + x.Value).ToArray())}"); | |
var elapsed = DateTime.Now - startTime; | |
Console.WriteLine($"seconds elapsed: {elapsed.TotalSeconds}"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment