Created
August 4, 2014 13:57
-
-
Save bencoveney/eb09ec79cd1e6ea907e9 to your computer and use it in GitHub Desktop.
Poker hands
This file contains 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.IO; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.Numerics; | |
using System.Threading.Tasks; | |
namespace EulerProject | |
{ | |
class Program | |
{ | |
#region Card | |
/// <summary> | |
/// A playing card | |
/// </summary> | |
class Card | |
{ | |
/// <summary> | |
/// Initializes a new instance of the <see cref="Card"/> struct. | |
/// </summary> | |
/// <param name="suit">The suit.</param> | |
/// <param name="value">The value.</param> | |
public Card(string cardValue) | |
{ | |
char[] cardComponents = cardValue.ToCharArray(); | |
// Parse the card value | |
Value = Value.None; | |
switch (cardComponents[0]) | |
{ | |
case '2': | |
Value = Value.Two; | |
break; | |
case '3': | |
Value = Value.Three; | |
break; | |
case '4': | |
Value = Value.Four; | |
break; | |
case '5': | |
Value = Value.Five; | |
break; | |
case '6': | |
Value = Value.Six; | |
break; | |
case '7': | |
Value = Value.Seven; | |
break; | |
case '8': | |
Value = Value.Eight; | |
break; | |
case '9': | |
Value = Value.Nine; | |
break; | |
case 'T': | |
Value = Value.Ten; | |
break; | |
case 'J': | |
Value = Value.Jack; | |
break; | |
case 'Q': | |
Value = Value.Queen; | |
break; | |
case 'K': | |
Value = Value.King; | |
break; | |
case 'A': | |
Value = Value.Ace; | |
break; | |
default : | |
throw new ArgumentException("Invalid Card Value"); | |
} | |
// Parse the card's suit | |
Suit = Suit.None; | |
switch (cardComponents[1]) | |
{ | |
case 'C' : | |
Suit = Suit.Club; | |
break; | |
case 'S': | |
Suit = Suit.Spade; | |
break; | |
case 'H': | |
Suit = Suit.Heart; | |
break; | |
case 'D': | |
Suit = Suit.Diamond; | |
break; | |
default: | |
throw new ArgumentException("Invalid Card Suit"); | |
} | |
} | |
/// <summary> | |
/// Gets or sets the suit. | |
/// </summary> | |
/// <value> | |
/// The suit. | |
/// </value> | |
public Suit Suit { get; private set; } | |
/// <summary> | |
/// Gets or sets the value. | |
/// </summary> | |
/// <value> | |
/// The value. | |
/// </value> | |
public Value Value { get; private set; } | |
} | |
/// <summary> | |
/// A card's suit | |
/// </summary> | |
enum Suit | |
{ | |
None, | |
Club, | |
Spade, | |
Heart, | |
Diamond, | |
} | |
/// <summary> | |
/// A card's value | |
/// </summary> | |
enum Value | |
{ | |
None, | |
Two = 2, | |
Three = 3, | |
Four = 4, | |
Five = 5, | |
Six = 6, | |
Seven = 7, | |
Eight = 8, | |
Nine = 9, | |
Ten = 10, | |
Jack = 11, | |
Queen = 12, | |
King = 13, | |
Ace = 14, | |
} | |
#endregion | |
#region Hand | |
class Hand | |
{ | |
public Hand(List<Card> cards) | |
{ | |
Cards = cards; | |
} | |
public List<Card> Cards { get; private set; } | |
public List<Value> CardValues { | |
get | |
{ | |
List<Value> values = new List<Value>(); | |
Cards.ForEach(x => values.Add(x.Value)); | |
return values; | |
} | |
} | |
public bool isBetterThan(Hand otherHand) | |
{ | |
// check for royal flushes | |
if (this.hasRoyalFlush() && !otherHand.hasRoyalFlush()) return true; | |
if (!this.hasRoyalFlush() && otherHand.hasRoyalFlush()) return false; | |
if (this.hasRoyalFlush() && otherHand.hasRoyalFlush()) return this.beatsHandOnHighValues(otherHand); | |
// If one hand has a straight flush and the other doesnt | |
if (this.hasStraightFlush() && !otherHand.hasStraightFlush()) return true; | |
if (!this.hasStraightFlush() && otherHand.hasStraightFlush()) return false; | |
if (this.hasStraightFlush() && otherHand.hasStraightFlush()) return this.beatsHandOnHighValues(otherHand); | |
// If one hand has a four of a kind and the other doesnt | |
if (this.hasFourOfAKind() && !otherHand.hasFourOfAKind()) return true; | |
if (!this.hasFourOfAKind() && otherHand.hasFourOfAKind()) return false; | |
if (this.hasFourOfAKind() && otherHand.hasFourOfAKind()) return this.beatsHandOnHighValues(otherHand); | |
// If one hand has a full house and the other doesnt | |
if (this.hasFullHouse() && !otherHand.hasFullHouse()) return true; | |
if (!this.hasFullHouse() && otherHand.hasFullHouse()) return false; | |
if (this.hasFullHouse() && otherHand.hasFullHouse()) return this.beatsHandOnHighValues(otherHand); | |
// If one hand has a flush and the other doesnt | |
if (this.hasFlush() && !otherHand.hasFlush()) return true; | |
if (!this.hasFlush() && otherHand.hasFlush()) return false; | |
if (this.hasFlush() && otherHand.hasFlush()) return this.beatsHandOnHighValues(otherHand); | |
// If one hand has a _ and the other doesnt | |
if (this.hasStraight() && !otherHand.hasStraight()) return true; | |
if (!this.hasStraight() && otherHand.hasStraight()) return false; | |
if (this.hasStraight() && otherHand.hasStraight()) return this.beatsHandOnHighValues(otherHand); | |
// If one hand has a _ and the other doesnt | |
if (this.hasThreeOfAKind() && !otherHand.hasThreeOfAKind()) return true; | |
if (!this.hasThreeOfAKind() && otherHand.hasThreeOfAKind()) return false; | |
if (this.hasThreeOfAKind() && otherHand.hasThreeOfAKind()) return this.beatsHandOnHighValues(otherHand); | |
// If one hand has a _ and the other doesnt | |
if (this.hasTwoPair() && !otherHand.hasTwoPair()) return true; | |
if (!this.hasTwoPair() && otherHand.hasTwoPair()) return false; | |
if (this.hasTwoPair() && otherHand.hasTwoPair()) return this.beatsHandOnHighValues(otherHand); | |
// If one hand has a _ and the other doesnt | |
if (this.hasOnePair() && !otherHand.hasOnePair()) return true; | |
if (!this.hasOnePair() && otherHand.hasOnePair()) return false; | |
if (this.hasOnePair() && otherHand.hasOnePair()) return this.beatsHandOnHighValues(otherHand); | |
return this.beatsHandOnHighValues(otherHand); | |
} | |
/// <summary> | |
/// </summary> | |
/// <param name="hand"></param> | |
/// <returns></returns> | |
private bool beatsHandOnHighValues(Hand hand) | |
{ | |
// relying on high values | |
// Console.WriteLine("Hand 1: {0} | Hand 2: {1}", this.ToString(), hand.ToString()); | |
// Get sorted values | |
List<Value> sortedValues = CardValues; | |
sortedValues.Sort(); | |
sortedValues.Reverse(); | |
List<Value> otherHandSortedValues = hand.CardValues; | |
otherHandSortedValues.Sort(); | |
otherHandSortedValues.Reverse(); | |
// if theres 4 of a kind | |
if (this.getQuadValues().Count() > 0) | |
{ | |
// Compare them | |
if (this.getQuadValues()[0] > hand.getQuadValues()[0]) return true; | |
if (this.getQuadValues()[0] < hand.getQuadValues()[0]) return false; | |
} | |
// if theres 3 of a kind | |
if (this.getTripleValues().Count() > 0) | |
{ | |
// Compare them | |
if (this.getTripleValues()[0] > hand.getTripleValues()[0]) return true; | |
if (this.getTripleValues()[0] < hand.getTripleValues()[0]) return false; | |
} | |
// if there are pairs | |
if (this.getPairedValues().Count() > 0) | |
{ | |
// get the values where pairs occur | |
List<Value> pairs = getPairedValues(); | |
pairs.Sort(); | |
pairs.Reverse(); | |
List<Value> otherPairs = hand.getPairedValues(); | |
otherPairs.Sort(); | |
otherPairs.Reverse(); | |
// for each value | |
for (int i = 0; i < pairs.Count(); i++) | |
{ | |
// Compare them | |
if (pairs[i] > otherPairs[i]) return true; | |
if (pairs[i] < otherPairs[i]) return false; | |
} | |
} | |
for (int i = 0; i < Cards.Count(); i++) | |
{ | |
// If this hand's card is higher then succeed | |
if (sortedValues[i] > otherHandSortedValues[i]) | |
return true; | |
// If the other hand's card is higher then fail | |
if (otherHandSortedValues[i] > sortedValues[i]) | |
return false; | |
} | |
return false; | |
} | |
/// <summary> | |
/// determines whether the had is a consecutive sequence of 1 type going from ten to ace | |
/// </summary> | |
/// <returns></returns> | |
private bool hasRoyalFlush() | |
{ | |
// if not a straight flush this cant be a royal flush | |
if (!hasStraightFlush()) return false; | |
// Get a list of all card values | |
List<int> values = new List<int>(); | |
Cards.ForEach(x => values.Add((int)x.Value)); | |
// Check the lowest card is a 10 | |
if (values.Min() != 10) return false; | |
// Check the highest card is an ace | |
if (values.Max() != 14) return false; | |
return true; | |
} | |
/// <summary> | |
/// determines whether the hand is a consecutive sequence of 1 type | |
/// </summary> | |
/// <returns></returns> | |
private bool hasStraightFlush() | |
{ | |
return (hasStraight() && hasFlush()); | |
} | |
/// <summary> | |
/// determines whether the hand has a 4 of a kind | |
/// </summary> | |
/// <returns></returns> | |
private bool hasFourOfAKind() | |
{ | |
return getQuadValues().Count() == 1 ? true : false; | |
} | |
private List<Value> getQuadValues() | |
{ | |
// Get a list of each card's value | |
List<Value> Values = new List<Value>(); | |
Cards.ForEach(x => Values.Add(x.Value)); | |
// Foreach possible card value find out if it is a quad | |
List<Value> quads = new List<Value>(); | |
foreach (Value value in (Value[])Enum.GetValues(typeof(Value))) | |
{ | |
// test for quad | |
// quit after finding one, there wont be any more | |
if (Values.Where(x => x == value).Count() == 4) quads.Add(value); | |
} | |
return quads; | |
} | |
/// <summary> | |
/// determines whether the hand has 1 pair and 1 triple | |
/// </summary> | |
/// <returns></returns> | |
private bool hasFullHouse() | |
{ | |
return (hasOnePair() && hasThreeOfAKind()); | |
} | |
/// <summary> | |
/// determines whether the cards are all the same type | |
/// </summary> | |
/// <returns></returns> | |
private bool hasFlush() | |
{ | |
// Get the suit of a card | |
Suit suit = Cards.First().Suit; | |
// If the cards dont all match that suit then fail | |
if (Cards.Where(x => x.Suit == suit).Count() != Cards.Count) return false; | |
return true; | |
} | |
/// <summary> | |
/// determines whether the cards are a consecutive sequence | |
/// </summary> | |
/// <returns></returns> | |
private bool hasStraight() | |
{ | |
// Get a list of card values | |
List<int> values = new List<int>(); | |
Cards.ForEach(x => values.Add((int)x.Value)); | |
// If the cards arent all distinct then fail | |
if (values.Distinct().Count() != Cards.Count) return false; | |
// If the cards arent consecutive then fail | |
if (values.Max() - values.Min() != (Cards.Count-1)) return false; | |
return true; | |
} | |
/// <summary> | |
/// determines whether the hand has a 3 of a kind | |
/// </summary> | |
/// <returns></returns> | |
private bool hasThreeOfAKind() | |
{ | |
return getTripleValues().Count() == 1 ? true : false; | |
} | |
private List<Value> getTripleValues() | |
{ | |
// Get a list of each card's value | |
List<Value> Values = new List<Value>(); | |
Cards.ForEach(x => Values.Add(x.Value)); | |
// Foreach possible card value find out if it is a quad | |
List<Value> triples = new List<Value>(); | |
foreach (Value value in (Value[])Enum.GetValues(typeof(Value))) | |
{ | |
// test for quad | |
// quit after finding one, there wont be any more | |
if (Values.Where(x => x == value).Count() == 3) triples.Add(value); | |
} | |
return triples; | |
} | |
/// <summary> | |
/// Determines whether the hand has exactly 1 pair. | |
/// </summary> | |
/// <returns></returns> | |
private bool hasOnePair() | |
{ | |
return getPairedValues().Count() == 1 ? true : false; | |
} | |
/// <summary> | |
/// Determines whether the hand has exactly 2 pairs. | |
/// </summary> | |
/// <returns></returns> | |
private bool hasTwoPair() | |
{ | |
return getPairedValues().Count() == 2 ? true : false; | |
} | |
/// <summary> | |
/// Returns the number of pairs in a hand | |
/// </summary> | |
/// <returns></returns> | |
private List<Value> getPairedValues() | |
{ | |
// Get a list of each card's value | |
List<Value> Values = new List<Value>(); | |
Cards.ForEach(x => Values.Add(x.Value)); | |
// Foreach possible card value find out if it is a pair | |
List<Value> pairs = new List<Value>(); | |
foreach (Value value in (Value[])Enum.GetValues(typeof(Value))) | |
{ | |
// test for pair | |
if (Values.Where(x => x == value).Count() == 2) pairs.Add(value); | |
} | |
return pairs; | |
} | |
public override string ToString() | |
{ | |
StringBuilder result = new StringBuilder(); | |
foreach (Card c in Cards) | |
{ | |
switch (c.Suit) | |
{ | |
case Suit.None: | |
default : | |
result.Append("ERROR"); | |
break; | |
case Suit.Club: | |
result.Append("C"); | |
break; | |
case Suit.Spade: | |
result.Append("S"); | |
break; | |
case Suit.Heart: | |
result.Append("H"); | |
break; | |
case Suit.Diamond: | |
result.Append("D"); | |
break; | |
} | |
switch (c.Value) | |
{ | |
default: | |
case Value.None: | |
result.Append("ERROR"); | |
break; | |
case Value.Two: | |
result.Append("2"); | |
break; | |
case Value.Three: | |
result.Append("3"); | |
break; | |
case Value.Four: | |
result.Append("4"); | |
break; | |
case Value.Five: | |
result.Append("5"); | |
break; | |
case Value.Six: | |
result.Append("6"); | |
break; | |
case Value.Seven: | |
result.Append("7"); | |
break; | |
case Value.Eight: | |
result.Append("8"); | |
break; | |
case Value.Nine: | |
result.Append("9"); | |
break; | |
case Value.Ten: | |
result.Append("T"); | |
break; | |
case Value.Jack: | |
result.Append("J"); | |
break; | |
case Value.Queen: | |
result.Append("Q"); | |
break; | |
case Value.King: | |
result.Append("K"); | |
break; | |
case Value.Ace: | |
result.Append("A"); | |
break; | |
} | |
result.Append(","); | |
} | |
return result.ToString(); | |
} | |
} | |
#endregion | |
/// <summary> | |
/// Mains the specified arguments. | |
/// </summary> | |
/// <param name="args">The arguments.</param> | |
[STAThread] | |
static void Main(string[] args) | |
{ | |
// Read all lines | |
List<string> lines = File.ReadAllLines("poker.txt").ToList(); | |
// For each line read the hands | |
int numOfWinsForPlayerOne = 0; | |
int numOfWinsForPlayerTwo = 0; | |
foreach (string line in lines) | |
{ | |
// Split into parts | |
List<string> lineParts = line.Split(' ').ToList(); | |
// Parse parts as cards | |
List<Card> cards = new List<Card>(); | |
lineParts.ForEach(x => cards.Add(new Card(x))); | |
// create the hands | |
Hand PlayerOne = new Hand(cards.GetRange(0, 5)); | |
Hand PlayerTwo = new Hand(cards.GetRange(5, 5)); | |
// Compare the hands | |
if (PlayerOne.isBetterThan(PlayerTwo)) | |
{ | |
numOfWinsForPlayerOne++; | |
} | |
if (PlayerTwo.isBetterThan(PlayerOne)) | |
{ | |
numOfWinsForPlayerTwo++; | |
} | |
} | |
Console.WriteLine("Player 1 wins: {0}", numOfWinsForPlayerOne); | |
Console.WriteLine("Player 2 wins: {0}", numOfWinsForPlayerTwo); | |
Console.WriteLine(numOfWinsForPlayerOne + numOfWinsForPlayerTwo); | |
Tests(); | |
Console.Read(); | |
} | |
/// <summary> | |
/// Testses this instance. | |
/// </summary> | |
static void Tests() | |
{ | |
// All same but 5 | |
RunTest("9C 8C 6D 5C 3C", "9C 8C 6D 5C 2C", true); | |
// All same but 4 | |
RunTest("9C 8C 6D 5C 3C", "9C 8C 6D 4C 3C", true); | |
// All same but 3 | |
RunTest("9C 8C 7D 5C 3C", "9C 8C 6D 5C 3C", true); | |
// All same but 2 | |
RunTest("9C 8C 6D 5C 3C", "9C 7C 6D 5C 3C", true); | |
// All same but 1 | |
RunTest("9C 7C 6D 5C 3C", "8C 7C 6D 5C 3C", true); | |
// Quads above diff | |
RunTest("AC AC AD AC KC", "AC AC AD AC QC", true); | |
// Quads below diff | |
RunTest("QC QC QD QC AC", "QC QC QD QC KC", true); | |
// Triples above diff highest high | |
RunTest("AC AC AD KC QC", "AC AC AD KC JC", true); | |
// Triples above diff lowest high | |
RunTest("AC AC AD KC QC", "AC AC AD KC JC", true); | |
// Triples between diff highest high | |
RunTest("QC QC QD AC JC", "QC QC QD KC JC", true); | |
// Triples between diff lowest high | |
RunTest("QC QC QD AC JC", "QC QC QD AC TC", true); | |
// Triples below diff highest high | |
RunTest("9C 9C 9D AC JC", "9C 9C 9D KC JC", true); | |
// Triples below diff lowest high | |
RunTest("9C 9C 9D AC QC", "9C 9C 9D AC JC", true); | |
// Full House | |
RunTest("9C 9C 9D JC JC", "9C 9C 9D TC TC", true); | |
// Full House | |
RunTest("9C 9C 9D TC TC", "9C 9C 9D 8C 8C", true); | |
// Full House | |
RunTest("9C 9C 9D 8C 8C", "9C 9C 9D 7C 7C", true); | |
} | |
static void RunTest(string hand1, string hand2, bool isHand1Winner) | |
{ | |
// Split into parts | |
List<string> hand1Parts = hand1.Split(' ').ToList(); | |
List<string> hand2Parts = hand2.Split(' ').ToList(); | |
// Parse parts as cards | |
List<Card> hand1cards = new List<Card>(); | |
hand1Parts.ForEach(x => hand1cards.Add(new Card(x))); | |
List<Card> hand2cards = new List<Card>(); | |
hand2Parts.ForEach(x => hand2cards.Add(new Card(x))); | |
// create the hands | |
Hand PlayerOne = new Hand(hand1cards); | |
Hand PlayerTwo = new Hand(hand2cards); | |
if (PlayerOne.isBetterThan(PlayerTwo) != isHand1Winner || PlayerTwo.isBetterThan(PlayerOne) == isHand1Winner) | |
{ | |
Console.WriteLine("Hand1: {0} Hand2: {1}", hand1.ToString(), hand2.ToString()); | |
} | |
else | |
{ | |
Console.WriteLine("Tests Passed"); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment