Skip to main content
2 of 2
replaced http://codereview.stackexchange.com/ with https://codereview.stackexchange.com/

Poker Hand classifer part 3: Deck Object and 7 Card Hand

Part 1: Beginnings of a Poker hand classifier Part 2: Beginnings of a Poker hand classifier part 2

I'm a beginner programmer, working on learning c# and object orientation and have been working on a poker hand classifier for practice. I've expanded my class since last part and made some decisions that i would really like feedback on.

Note: I May not have done all the ideas suggested to me, This was either because I had to make changes to classes/method and the ideas no longer worked or it was a bit beyond me.

Deck Object class and 2 hand class inheriting hand

 public class Deck
{
    static Random rand = new Random();
    public List<Card> Cards { get; private set; }
    public Deck()
    {
        Cards = new List<Card>();
        FillDeck(this);
    }
    private static void FillDeck(Deck deck)
    {
        Face[] faceNames = { Face.Ace, Face.Two, Face.Three, Face.Four, Face.Five, Face.Six, Face.Seven, Face.Eight, Face.Nine, Face.Ten, Face.Jack, Face.Queen, Face.King };
        Suit[] allSuits = { Suit.Diamond, Suit.Club, Suit.Heart, Suit.Spade };

        foreach (Suit suit in allSuits)
        {
            foreach (Face face in faceNames)
            {
                deck.Cards.Add(new Card(suit, face));
            }
        }
        ShuffleDeck(deck);
    }
    public static void ShuffleDeck(Deck deck)
    {    
        for (int i = 1; i <= deck.Cards.Count; i++)
        {
            PerformCardSwap(deck);
        }
    }
    private static void PerformCardSwap(Deck deck)
    {
        int randomIndex = rand.Next(1, deck.Cards.Count);
        Card firstCard = deck.Cards[0];
        Card randomCard = deck.Cards[randomIndex];
        deck.Cards[0] = randomCard;
        deck.Cards[randomIndex] = firstCard;
    }
    public static List<Card> Deal5Cards(Deck deck)
    {
        List<Card> newHand = new List<Card>();
        for (int i = 0; i < 5; i++)
        {
            Card temp = deck.Cards[0];
            newHand.Add(temp);
            deck.Cards.RemoveAt(0);
        }
        return newHand;

    }
    public static List<Card> Deal2Cards(Deck deck)
    {
        List<Card> newHand = new List<Card>();
        for (int i = 0; i < 2; i++)
        {
            Card temp = deck.Cards[0];
            newHand.Add(temp);
            deck.Cards.RemoveAt(0);
        }
        return newHand;

    }
}
public class TwoCardHand : Hand
{
    public new List<Card> Cards { get; }
    public TwoCardHand(List<Card> cards)
    {
        if (cards.Count != 2)
        {
            throw new ArgumentOutOfRangeException("Invalid amount of Cards");
        }
        Cards = new List<Card>(cards);

    }
    public TwoCardHand()
    {
        Cards = Deck.Deal2Cards(deck);
    }
}

Is this the best way to "shuffle the deck"? I seem to have a lot of diamond suits by chance during testing. Inheriting Hand was required to ensure they have the same static deck object property so they did not draw the same cards. Is this bad programming, I Couldn't think of another way to do this...

Hand Object - a lot of changes especially inside compare to. Which now sorts pairing value correctly and provides the best possible hand from 21 sets of hands.

 public class Hand : IComparable<Hand>
{
    public static Deck deck = new Deck();
    public List<Card> Cards { get; private set; }
    public PokerHandsRank HandRank
    {
        get { return CheckHandRank(this);  }
    }
    public Hand(List<Card> cards)
    {
        if (cards.Count != 5)
        {
            throw new ArgumentOutOfRangeException("Invalid amount of Cards");
        }
        Cards = new List<Card>(cards);
    }
    public Hand()
    {
        this.Cards = Deck.Deal5Cards(deck);
    }
    public override string ToString()
    {
        sortHandbyFaceDesc(this);
        return string.Join(" ", Cards.Select(c => $"({c.Face} of {c.Suit}'s)"));     
    }
    private static int SortandCompareFaceValues(Hand hand, Hand secondhand)
    {
        sortHandbyFaceDesc(hand);
        sortHandbyFaceDesc(secondhand);
        for (int i = 4; 0 <= i; i--)
        {
            if (hand.Cards[i].Face == secondhand.Cards[i].Face)
            {
                if (i == 0) return 0;
                continue;
            }
            return hand.Cards[i].Face > secondhand.Cards[i].Face ? 1 : -1;
        }
        return 0; // should never get here but how to handle
    }
    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
        {
            if (HandRank.Equals(PokerHandsRank.Pair) || HandRank.Equals(PokerHandsRank.TwoPair) || HandRank.Equals(PokerHandsRank.ThreeOfKind) || HandRank.Equals(PokerHandsRank.FullHouse) || HandRank.Equals(PokerHandsRank.FourOfKind))
            {                    
                int pairValue = (ComparePairValue(this, other)); //check the values of the pairs and judge which is highest value
                return pairValue == 0  ? SortandCompareFaceValues(this, other) :  pairValue; //if pair is equal rank and highest value is equal check for highcards
            }
            return SortandCompareFaceValues(this, other);
        }
        return HandRank > other.HandRank ? 1 : -1;
    }
    private static int ComparePairValue(Hand hand, Hand secondHand)
    {
        Face face1 = FindHighestPairValuesFace(hand);
        Face face2 = FindHighestPairValuesFace(secondHand);

        return face1 == face2 ? 0 : face1 > face2 ? 1 : -1;
    }
    private static Face FindHighestPairValuesFace(Hand hand)
    {
        return (from card in hand.Cards
                orderby card.Face descending //sort by face value first
                group card by new { card.Face } into g
                let count = g.Count()
                orderby count descending // sort by what cards appear the most
                select new { g.Key.Face }.Face).First(); //first is highest value pair that appears the most
    }
    public static void sortHandbyFaceDesc(Hand hand)
    {
        var sortCards = (from cards in hand.Cards
                         orderby cards.Face descending
                         select cards).ToList();
        hand.Cards = sortCards;
    }
    public static void sortHandbyFace(Hand hand)
    {
        var sortCards = (from cards in hand.Cards
                         orderby cards.Face
                         select cards).ToList();
        hand.Cards = sortCards;
    }    

Pokerhandchecker is not included to save space, see part 2 if you wish to view them logic to find all possible hands then best hand

      private static Hand findBestHandInList(List<Hand> possibleHands)
    {
        // return  possibleHands.OrderByDescending(h => h.HandRank).First().Cards;
        Hand returnList = new Hand(possibleHands[0].Cards);
        for (int i = 0; i < possibleHands.Count - 1; i++)
        {
            if (returnList.CompareTo(possibleHands[i + 1]) == -1)
            {
                returnList = possibleHands[i + 1];
            }
        }
        return returnList;
    }
    private static void addPossibleHandFromSevenCards(List<Card> cards, List<Hand> possibleHands)
    {
        List<Card> tempCardList = new List<Card>();  // select first card not to be in the hand
        for (int firstCard = 0; firstCard < cards.Count; firstCard++)
        {
            for (int secondCard = firstCard + 1; secondCard < cards.Count; secondCard++) // select first card not to be in the hand
            {
                for (int i = 0; i < cards.Count; i++)
                {
                    if (i != firstCard && i != secondCard) // every card that is not the first or second will added to the hand
                    {
                        tempCardList.Add(cards[i]);
                    }
                }
                possibleHands.Add(new Hand(tempCardList));
                tempCardList.Clear();
            }
        }
    }

Main Program Code to run the console.

        Console.BackgroundColor = ConsoleColor.DarkGreen;
        Console.ForegroundColor = ConsoleColor.White;
        Console.Clear();
        Hand tableHand = new Hand();
        Console.WriteLine("Cards on the table are:");
        PrintCards(tableHand);


        TwoCardHand your2Cards = new TwoCardHand();
        TwoCardHand their2Cards = new TwoCardHand();
        Console.WriteLine();
        Console.WriteLine("Your two cards are:");
        PrintCards(your2Cards.Cards);
        Console.WriteLine("Their two cards are:");
        PrintCards(their2Cards.Cards);
        Console.WriteLine();
        Console.Read();
        List<Card> YourSevenHand = new List<Card>(your2Cards.Cards.Concat(tableHand.Cards));
        List<Card> TheirSevenHand = new List<Card>(their2Cards.Cards.Concat(tableHand.Cards));

        List<Hand> yourPossibleHands = new List<Hand>();
        List<Hand> theirPossibleHands = new List<Hand>();

        addPossibleHandFromSevenCards(YourSevenHand, yourPossibleHands);
        addPossibleHandFromSevenCards(TheirSevenHand, theirPossibleHands);

        Hand yourFinalHand = findBestHandInList(yourPossibleHands);               
        Hand theirFinalHand = findBestHandInList(theirPossibleHands);
                  
        Console.WriteLine(yourFinalHand.CompareTo(theirFinalHand) == 1 ? "You win" : yourFinalHand.CompareTo(theirFinalHand) == 0 ? "Draw" : "They win");

        Console.WriteLine(yourFinalHand);
        Console.WriteLine("You have a {0}", yourFinalHand.HandRank);
        Console.WriteLine(theirFinalHand);
        Console.WriteLine("They have a {0}", theirFinalHand.HandRank);

Am I Making too many instances here? can this be made better?

This will most likely be my last post on this project as I think I have reached the limit of my ability to expand it further. I genuinely appreciate all and any suggestions people have for my code.

If you wish to run it for yourself. Please see the card class, enums and Check hand rank in part 1 and 2 I believe they should still work.

Steve
  • 195
  • 7