Skip to content

Instantly share code, notes, and snippets.

@evgeniyp
Last active July 28, 2019 10:38
Show Gist options
  • Save evgeniyp/19f22bf9eecd46d8868500550d5feb09 to your computer and use it in GitHub Desktop.
Save evgeniyp/19f22bf9eecd46d8868500550d5feb09 to your computer and use it in GitHub Desktop.
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