Things I learned about comparing two poker hands in C#

I’ve been going through Visual C# 2005: How to Program, 2/e and I recently got stuck on problem 30 in chapter 8. Chapter 8 deals with arrays and problem 30 is an innocent thing asking you to compare 2 hands of poker. Well, I spend a good month fucking around with this problem thinking to myself, there is NO WAY it should be this convoluted and hard. After finishing it yesterday, it turns out it is. The Coding the Wheel site has an entire page devoted to poker hand evaluations and my code looks remarkably like the naive implementation. My implementation is more difficult because beyond the initial hand evaluation, it tries to compare the hands and account for ties all the way down to a perfect tie, which in poker results in a pot split. I always thought suits would be used to break ties, but that isn’t an official rule according to Wikipedia. I found a few things significantly hampered me in my particular implementation.

  1. I should have developed using TDD. I developed the test code below AFTER I had written a significant portion of code, which killed me since I had to scrap a lot of that poorly tested code and rewrite my algorithms. I’ve posted a portion of the test code below. The only thing of note here is that I created an Enumeration called Hands which contained all of all the poker hands which I passed into this method.

    BuildHand method of DeckOfCardsTest class

     private void BuildHand(Card[] pokerHand, Hands typeOfHand) {
                int counter;
    
                string[] suits = { "Hearts", "Diamonds", "Clubs", "Spades" };
                string[] faces = { "Ace", "Deuce", "Three", "Four", "Five", "Six",
     "Seven", "Eight", "Nine", "Ten", "Jack", "Queen", "King" };
    
                // designate default suit 
    for cards as Hearts and default face as deuce
                string testSuit = suits[0];
                string testFace = faces[1];
    
                Card card;
    
                switch (Convert.ToInt32(typeOfHand)) {
                    // Create high card hand
                    case 0:
                        testSuit = suits[0];
                        for (counter = 0; counter < pokerHand.Length; ++counter) {
                            switch (counter) {
                                case 0:
                                    testFace = faces[2];
                                    testSuit = suits[3];
                                    break;
                                case 1:
                                    testFace = faces[9];
                                    testSuit = suits[1];
                                    break;
                                case 2:
                                    testFace = faces[12];
                                    testSuit = suits[2];
                                    break;
                                case 3:
                                    testFace = faces[4];
                                    testSuit = suits[3];
                                    break;
                                case 4:
                                    testFace = faces[random.Next(4,9)];
                                    testSuit = suits[1];
                                    break;
                            }
                            card = new Card(testFace, testSuit);
                            pokerHand[counter] = card;
                        }
                        break;
                    // Create pair hand
                    case 1:
                        int pair = random.Next(0, 7);
                        for (counter = 0; counter < pokerHand.Length; ++counter) {
                            switch (counter) {
                                case 0:
                                    testFace = faces[pair];
                                    testSuit = suits[0];
                                    break;
                                case 1:
                                    testFace = faces[pair];
                                    testSuit = suits[1];
                                    break;
                                case 2:
                                    testFace = faces[7];
                                    testSuit = suits[2];
                                    break;
                                case 3:
                                    testFace = faces[9];
                                    testSuit = suits[3];
                                    break;
                                case 4:
                                    testFace = faces[10];
                                    testSuit = suits[1];
                                    break;
                            }
                            card = new Card(testFace, testSuit);
                            pokerHand[counter] = card;
                        }
                        break;                
  2. I REALLY should have implemented a HandOfPoker class instead of using a Card array directly. This would have cleaned up my code quite a bit because each HandOfPoker object could have contained the frequency arrays I was using to store my face and suit counts. I also could have stored the hand results directly as properties instead of having to immediately compare after evaluation. See some of my ugly code below. Notice the massive redundancy as I compare the two hands. Sorry about some of the code getting cut off, but I can’t make it appear without ruining the formatting which will make it impossible to read. It’s not really for analysis, but to demonstrate what I could have improved.
    CompareTwoHands method from DeckOfCards class
    public void CompareTwoHands(Card[] firstHand, Card[] secondHand) {
                Hands firstHandResult;
                Hands secondHandResult;
    
                int counter;
                int cardCounter;
                int highestCardCount;
    
                int firstHandHighCard = faceValues.Length;
                int secondHandHighCard = faceValues.Length;
    
                // for each hand we will create 
    a frequency array for the faces (13) and suits (4)
                int[] faceCountsFirstHand;
                int[] suitCountsFirstHand;
    
                int[] faceCountsSecondHand;
                int[] suitCountsSecondHand;
    
                faceCountsFirstHand = CountFaceCards(firstHand);
                suitCountsFirstHand = CountSuitCards(firstHand);
    
                faceCountsSecondHand = CountFaceCards(secondHand);
                suitCountsSecondHand = CountSuitCards(secondHand);
    
                firstHandResult = 
    		AssessHand(faceCountsFirstHand, suitCountsFirstHand);
                secondHandResult = 
    		AssessHand(faceCountsSecondHand, suitCountsSecondHand);
    
                if (firstHandResult > secondHandResult) {
                    Console.WriteLine("The first hand won with "
     + DisplayHand(firstHandResult,faceCountsFirstHand,suitCountsFirstHand) + 
    " beating " +
     DisplayHand(secondHandResult,faceCountsSecondHand,suitCountsSecondHand));
                }
                else if (firstHandResult < secondHandResult) {
                    Console.WriteLine("The second hand won with " + 
    DisplayHand(secondHandResult,faceCountsSecondHand,suitCountsSecondHand) + " beating " +
     DisplayHand(firstHandResult,faceCountsFirstHand,suitCountsFirstHand));
                }
                else if (firstHandResult == secondHandResult) {
                    switch (Convert.ToInt32(firstHandResult)) {
                        case 1:
                            highestCardCount = 2;
                            for (cardCounter = highestCardCount; cardCounter > 0; --cardCounter) {
                                for (counter = faceCountsFirstHand.Length - 1; counter > 0; --counter) {
                                    if (faceCountsFirstHand[0] == highestCardCount || faceCountsSecondHand[0] == highestCardCount) {
                                        if (faceCountsFirstHand[counter] != faceCountsSecondHand[counter]) {
                                            firstHandHighCard = faceCountsFirstHand[counter];
                                            secondHandHighCard = faceCountsSecondHand[counter];
                                            cardCounter = 0;
                                            break;
                                        }
                                    }
                                    else if (faceCountsFirstHand[counter] == highestCardCount || faceCountsSecondHand[counter] == highestCardCount) {
                                        if (faceCountsFirstHand[counter] != faceCountsSecondHand[counter]) {
                                            firstHandHighCard = faceCountsFirstHand[counter];
                                            secondHandHighCard = faceCountsSecondHand[counter];
                                            cardCounter = 0;
                                            break;
                                        }
                                    }
                                }
                                if (counter == 1 && firstHandHighCard == secondHandHighCard) {
                                    highestCardCount = highestCardCount - 1;
                                }
                            }
                            break;

 

But you  know what? After doing all this, I’m pretty content with finishing it. I’m really fired up about what I learned, and after looking over some of the better solutions on Coding the Wheel, I realize that my solution is hampered by my tools, in this case my tool being the data structure Array which I’m being asked to use exclusively ( and I don’t really know anything else either. 🙂 ).

Hope this helps someone else trying to learn about this problem!

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s