Part 1 - Beginnings of a Poker hand classifier
I'm a beginner programmer I've been working on a poker hand classifier to improve my object orientation and programming skills, I've improved and expanded my class from last time and wanted to share and see if what I've done could be improved.
Card Class, Hand Class, enums for suit, handrank and face
public class Hand : IComparable<Hand>
{
public List<Card> Cards { get; }
public PokerHandsRank HandRank { get; set; }
public Hand(List<Card> cards)
{
if (cards.Count() == 5)
{
Cards = cards;
HandRank = PokerHandsRank.HighCard;
}
else
{
throw new Exception("Invalid amount of Cards");
}
}
public override string ToString()
{
return string.Format(
"(" + Cards[0].Face + " of " + Cards[0].Suit + "s) "
+ "(" + Cards[1].Face + " of " + Cards[1].Suit + "s) "
+ "(" + Cards[2].Face + " of " + Cards[2].Suit + "s) "
+ "(" + Cards[3].Face + " of " + Cards[3].Suit + "s) "
+ "(" + Cards[4].Face + " of " + Cards[4].Suit + "s) "
);
}
public int CompareTo(Hand other)
{
if (HandRank == other.HandRank) //if the hand rank is equal, sort the cards by face value and compare the two biggest
{
Hand sortThisHand = Program.sortHandbyFace(this);
Hand sortOtherHand = Program.sortHandbyFace(other);
if (sortThisHand.Cards[4].Face > sortOtherHand.Cards[4].Face)
return 1;
else if (sortThisHand.Cards[4].Face < sortOtherHand.Cards[4].Face)
return -1;
else
return 0;
}
else if (HandRank > other.HandRank)
return 1;
else if (HandRank < other.HandRank)
return -1;
else
throw new Exception("Hand rank is not initiated");
}
}
public class Card
{
public Face Face { get; }
public Suit Suit { get; }
public Card(Suit suit, Face face)
{
Face = face;
Suit = suit;
}
public override string ToString()
{
string card = "(" + Face + " of " + Suit + "s) ";
return card;
}
}
public enum Face
{
Two,
Three,
Four,
Five,
Six,
Seven,
Eight,
Nine,
Ten,
Jack,
Queen,
King,
Ace
}
public enum Suit
{
Club, Diamond, Heart, Spade
}
public enum PokerHandsRank
{
HighCard,
Pair,
TwoPair,
ThreeOfKind,
Straight,
Flush,
FullHouse,
FourOfKind,
StraightFlush,
RoyalFlush
}
note: I had a lot trouble with initializing the handrank by using the checkHandRank Method(stack overflow exception) so I had to leave it at the minimum enum of highcard and run the checkhand method in main program class but its definitely not right in my opinion.
CheckHandRank and sortHandByFace Methods
public static PokerHandsRank CheckHandRank(Hand hand)
{
PokerHandsRank flushCheck = CheckHandForFlush(hand);
PokerHandsRank pairCheck = CheckHandForPairs(hand);
PokerHandsRank straightCheck = CheckHandForStraight(hand);
if (flushCheck == PokerHandsRank.Flush && straightCheck == PokerHandsRank.Straight)
{
Hand sortedHand = sortHandbyFace(hand);
return sortedHand.Cards[4].Face == Face.Ace && sortedHand.Cards[0].Face != Face.Two ? PokerHandsRank.RoyalFlush : PokerHandsRank.StraightFlush;
}
if (pairCheck > flushCheck) return pairCheck; // check if pair rank is greater than flush rank (four of a kind or fullhouse) //returns either four of a kind or fullhouse
if (flushCheck == PokerHandsRank.Flush) return flushCheck; //return flush
return straightCheck == PokerHandsRank.Straight ? straightCheck : pairCheck; //returns straight or pair value (three of a kind, two pair, pair or highcard)
}
public static Hand sortHandbyFace(Hand hand)
{
var sortCards = (from cards in hand.Cards
orderby cards.Face
select cards);
List<Card> orderedCards = sortCards.ToList();
Hand sortedHand = new Hand(orderedCards);
return sortedHand;
}
check for flush/straights/pairs
private static PokerHandsRank CheckHandForFlush(Hand hand)
{
var suitCount = (from card in hand.Cards
group card by card.Suit into g
let count = g.Count()
orderby count descending
select count).Take(1).ToList();
flushName = hand.Cards[0].Suit;
return suitCount[0] == 5 ? PokerHandsRank.Flush : PokerHandsRank.HighCard;
}
private static PokerHandsRank CheckHandForStraight(Hand hand)
{
int cardsInARowCount = 0;
Hand orderedHand = sortHandbyFace(hand);
if (orderedHand.Cards[4].Face == Face.Ace && orderedHand.Cards[0].Face == Face.Two &&
orderedHand.Cards[1].Face == Face.Three && orderedHand.Cards[2].Face == Face.Four &&
orderedHand.Cards[3].Face == Face.Five) // check if ace, two, three, four, five straight
{
return PokerHandsRank.Straight;
}
for (int i = 0; i < orderedHand.Cards.Count - 1; i++) // check if the next card's face in the hand is the same as the next in the enum face order
{
if (orderedHand.Cards[i].Face + 1 == orderedHand.Cards[i + 1].Face)
{
cardsInARowCount++;
}
}
return cardsInARowCount == 4 ? PokerHandsRank.Straight : PokerHandsRank.HighCard;
}
private static PokerHandsRank CheckHandForPairs(Hand hand)
{
var faceCount = (from card in hand.Cards
group card by card.Face
into g
let count = g.Count()
orderby count descending
select count).Take(2).ToList(); // take two to check if multiple pairs of pairs, if second in list is 1 there will be two pairs
switch (faceCount[0])
{
case 1: return PokerHandsRank.HighCard;
case 2: return faceCount[1] == 1 ? PokerHandsRank.Pair : PokerHandsRank.TwoPair;
case 3: return faceCount[1] == 1 ? PokerHandsRank.ThreeOfKind : PokerHandsRank.FullHouse;
case 4: return PokerHandsRank.FourOfKind;
default: throw new Exception("something went wrong here");
}
}
If i wanted to get the name value of the pairs would that be possible? I tried using linq but by the time they are sorted into count they lose the card value therefore the face property.
I also have a few deck methods which fill/deal/removeatx/swapcard but they are basic and not particularly relevant but let me know if i should post them.
I plan to continue this program a bit more but this as a good point to review. I've spent 30-45mins testing and random decks seem to be read, written, sorted and compared with other hands well enough. Please let me know how it could be improved or if there are any errors thanks!