How to Code Poker Hands – Comparing Hands For A Two Pair

When you have two poker hands and both are a two pair, this article will show you how to compare them and determine which one ranks higher.

In a previous article for poker hands, you saw how to compare a hand to determine if a hand was a two pair. The pairs in the hand are made of two different values, and a fifth card with a different value from either of the pairs. Here’s an example of a two pair:

The is a “two pair, queens and fives”, and the kicker card is a jack.

When determining the winner between two hands that are both a two pair, the process is very similar to the pair’s, except we’re dealing with two pairs in each hand instead of one:

  1. Compare the values of each hand’s higher pair.
  2. If those values are equal, compare the values of each hand’s lower pair.
  3. If those are equal, compare the values of the final card (the “kickers” ) in each hand.
  4. Finally, if the kicker does not breaks the tie, then both hands are equal.

Let’s have a look at an example.

Hand 1
Hand 2

In hand 1, the value of its higher pair is five, and hand 2’s is six. So, hand 2 is the winner.

Now, consider these hands:

Hand 1
Hand 2

The higher pair in hand 1 has a value of five, and so does hand 2. So move onto the lower pair.

The value of hand 1’s lower pair is four, while hand 2’s is three. This time, hand 1 is the winner.

And if the values of the pairs in both hands are equal, then you’d go on to compare the final kicker card of each hand.

Wild Cards

But what about wild cards!? ๐Ÿ˜ฎ

Yeah, guess we shoulda seen that one comin’. ๐Ÿ˜‰

Remember that a wild card can assume the value of any card. If your hand has a pair of wilds in it, then both wilds can assume the highest value, ace. Have a look at this:

The suits of the aces don’t matter; wilds only care about card values in the case of a two pair.

If the hand only contained a pair one wild, and two other cards of different values, then the wild would assume other card with the higher value. So, if the hand was this:

The wild would assume the value of jack, because that’s the highest non-paired card. So the hand acts like:

This creates a challenge for us in a few ways, and we’ll need to make some changes to how two pairs are even matched in the first place.

Setup

Note: The first stages of the setup can be found on the introduction page to comparing poker hands, here.

There aren’t any other specific preparations we need before we begin.

Writing The Code For Comparing Two Pairs

When two hands are both a two pair, the GetWinningHandfunction will eventually call a function that compares both of these types of hands.

But before we do that, we’ll need a way to get the values of both pairs in a hand when we compare the hand to another two-pair hand.

Have a look at this hand:

If you go back to examine the psuedocode of the TwoPair function, you’ll see that it calls CardsHaveSameValue(sortedHand, 2, wildsInfo) twice. That’s because it’s checking to see if 2 cards have the same value twice.

There are two caveats to this function.

One is that it could find two pairs, where both pairs have the same value, something like:

While technically, this hand contains two pairs of cards, it’s not a two pair, because the pairs are the same value. Also, if you’ve implemented a system, where you’re matching hands, starting with the highest ranking hand and working down, this hand would always be matched as a four of a kind before ever being evaluated as a two pair.

The second caveat is that the info.cardValues array inside the parameter of CardsHaveSameValue does not report the correct value if our hand has only one pair and a wild. After calling CardsHaveSameValue twice, it would report the cardValues of the two cards found would be CardValues.JACK and CardValues.TWO! It should’ve reported CardValues.NINE instead! When you’re simply matching for a two pair hand, it doesn’t matter which card values get reported, since they aren’t used anyway. But if you’re comparing two hands of a two pair, that’s a whole ‘nother story. The correct values of the pairs are important.

We won’t make any adjustments to CardsHaveSameValue since it works well for out matching situations. We don’t want to break anything. So, getting the correct pairs will require some custom code for comparing two pairs.

Let’s begin, shall we? ๐Ÿ˜

Our main function, GetWinningHand will eventually call FindWinnerTwoPair to compare the hands. Just like the previous FindWinnerHighCard and FindWinnerJacksOrBetter functions from previous articles, FindWinnerTwoPair accepts two parameters, the hand for both players, and it’ll return the ID of the player who has the winning hand. If both hands are equal, it’ll return 0 (which we’ll use to mean a draw). The pseudocode below starts by comparing the values of the pairs first, then comparing the kickers if necessary.

FindWinnerTwoPair
FindWinnerTwoPair = function(hand1, hand2) {
  sortedHand1 = CardMatchUtils.SortCardsByDescendingValue(hand1);
  SET hand1Info to an empty object { }
  SetInfoAndCheckForTwoPair(hand1, hand1Info);

  sortedHand2 = CardMatchUtils.SortCardsByDescendingValue(hand2);
  SET hand2Info to an empty object { }
  SetInfoAndCheckForTwoPair(hand2, hand2Info);

  SET winningIndex = ComparePairs(hand1, hand1Info, hand2, hand2Info);
  IF (winningIndex NOT EQUAL TO -1)
    RETURN winningIndex (one hand's pairs outranks the other hand's, and no further checking is necessary)
  END

  (both hands have the same ranking pairs, now compare the kickers of both hands)
  SET winningIndex = CompareKickers(hand1, hand1Info, hand2, hand2Info);
  RETURN winningIndex;
}

The FindWinnerTwoPair function uses a few new functions, SetInfoAndCheckForTwoPair and ComparePairs, and we’ll get into those below.

Checking For A Two Pair And Getting The Pair Values

This function will check for a two pair with two unique values of pairs, and it will update the info parameter sent to it.

SetInfoAndCheckForTwoPair
SetInfoAndCheckForTwoPair = function(hand, info) {
  IF info not is specified
    SET info to an empty object { }
  END

  IF info does not contain the property cardValues
    SET info.cardValues to an empty array [ ]
  END

  SET valueCounts to CountCardValues(hand) (count the number of times each card value appears in the hand)
  FOR EACH valueCount found in valueCounts
    IF the number of times that value was found EQUALS two (valueCount.count == 2)
      add that card value to the end of the info.cardValues array
    END
  END

  IF the number of values in the info.cardValues array EQUALS two (info.cardValues.length == 2)
    (we have two pairs with unique values, so the two pair is satisfied, we can exit here with success)
    sort the values in info.cardValues in descending order (highest to lowest)
    RETURN TRUE
  END

  IF the number of values in the info.cardValues array EQUALS one (info.cardValues.length == 1)
    (only found one pair, check if the other pair could be formed using wilds, if any exist)

    (exclude the two cards that form the pair from the hand using the frst [and only] card value in the info.cardValues array)
    SET handMinusPair = CardMatchUtils.BuildHandExcludingValues(hand, 2, info.cardValues[0])

    IF CardMatchUtils.DoCardsHaveSameValue(handMinusPair, 2, info) == TRUE
      (There was a wild in the remaining three cards that formed a pair with the highest value. The DoCardsHaveSameValue will add that card's value
      onto the end of the info.cardValues array.)

      sort the values in info.cardValues in descending order (highest to lowest))
      RETURN TRUE
    END
  END

  (this hand is not a two pair, exit with failure)
  RETURN FALSE
}
Counting Card Values

This function counts how many times the values of each card in the hand appears. This is useful for counting pairs, and generic enough to put into CardMatchUtils.

CountCardValues
CardMatchUtils.CountCardValues = function(hand) {
  SET countValues to an empty array [ ]

  FOR EACH card in the hand
    FOR EACH countValueUnit in countValues
      IF countValueUnit.value EQUALS card.value
        ADD 1 onto countValueUnit.count
      END
    END

    IF none of the current count value units in countValues have a value that equals the card's value
      (add a new count value unit onto the countValues array with these values)
      countValues.push({
        value: card.value
        count: 1
      })
    END
  END

  RETURN countValues
}

Quite a lot here, right. Let’s have a closer look, shall we? ๐Ÿ™ƒ

First, have a look at SetInfoAndCheckForTwoPair. This function accepts two parameters:

  1. The hand of cards, already sorted in descending order, wilds last.
  2. An optional info parameter.

When the function first runs, if no info parameter is specified (which would be the case if you’re only matching for a two pair and not comparing it), then one is created for use of this function. Otherwise, the info object specified is used, and modified by this function (for later use). We also want to create a new cardValues array property inside the info object and set it to an empty array [ ].

After that, the function counts the number of times each card value appears in the hand. This introduces a new function that you can place in your CardMatchUtils called CountCardValues.

So if you looked at our previous hand:

When we count the values in it, the CountCardValues would return this array:

[
  {
    value: 11 (CardValue.jack),
    count: 2
  },

  {
    value: 9 (CardValue.nine),
    count: 1
  },

  {
    value: 2 (CardValue.two),
    count: 1
  },

  {
    value: 100 (CardValue.wild),
    count: 1
  }
]
Resolving The Pairs

Back to the SetInfoAndCheckForTwoPair function: for those elements in this array that have a count property of 2, add them those values to the info.cardValues array. In this case, only the pair of jacks was found, so your info.cardValues looks like [ 11 ].

Next, if after counting card values, our info.cardValues has exactly two elements in it, this means it found two pairs of unique values. So, we’ve satisfied the condition of a two pair, and we can exit with success.

However, as in our example, we only found one pair. So we need to check the remaining three cards.

At this point, CardMatchUtils.DoCardsHaveSameValue would not have any adverse side effects if we used it on the remaining three cards, because if a wild was one of them, it would assume the highest value between the other two cards.

It would be nice if we could temporarily remove the first pair so we could easily compare the remaining three. Fortunately, we already have a CardMatchUtils.BuildHandExcludingValues function that can do just that! ๐Ÿ˜Ž

So there is this line in the SetInfoAndCheckForTwoPair function:
SET handMinusPair = CardMatchUtils.BuildHandExcludingValues(hand, 2, info.cardValues[0])
It builds us a new temporary hand without the jacks in it (or whatever the value of the first pair was).

In SetInfoAndCheckForTwoPair, we can then go on to call:
CardMatchUtils.DoCardsHaveSameValue(handMinusPair, 2, info)
And if it returns TRUE, then:

  1. A pair formed using a wild was possible
  2. The info.cardValue array will be updated (by DoCardsHaveSameValue) which will contain the value that the wild assumed. In this case, a nine.

Finally, in SetInfoAndCheckForTwoPair just before, and if, it finds success, it sorts the values in the info.cardValues array in descending order (highest to lowest). It does this because when comparing the pairs of both hands, this makes comparisons easier, because we’ll be comparing the higher-ranking pair of one hand to the other hand’s higher-ranking pair. Then, if necessary, the lower-ranking pairs.

So when SetInfoAndCheckForTwoPair completes and it returns TRUE, not only will yo have a valid two-pair hand, but then you’ll also know the values of both pairs.

Comparing The Pairs

The next major function in FindWinnerTwoPair is ComparePairs. This will compare the values of the pairs of both hands and return 0 if the first hand wins, 1 if the second hand wins, or -1 if both hands are equal.

ComparePairs
ComparePairs = function(hand1, hand1Info, hand2, hand2Info) {
  (compare the higher-ranking pairs of each hand first)
  SET hand1WorkingPairValue = hand1Info.cardValues[0]
  IF hand1WorkingPairValue EQUALS WILD_VALUE
    hand1WorkingPairValue = ACE_VALUE

  SET hand2WorkingPairValue = hand2Info.cardValues[0]
  IF hand2WorkingPairValue EQUALS WILD_VALUE
    hand2WorkingPairValue = ACE_VALUE

  IF (hand1WorkingPairValue > hand2WorkingPairValue)
    RETURN 0 (hand 1's higher-ranking pair wins)
  ELSE IF (hand1WorkingPairValue < hand2WorkingPairValue)
    RETURN 1 (hand 2's higher-ranking pair wins)
  END

  (compare the lower-ranking pairs of each hand first)
  SET hand1WorkingPairValue = hand1Info.cardValues[1]
  IF hand1WorkingPairValue EQUALS WILD_VALUE
    hand1WorkingPairValue = ACE_VALUE

  SET hand2WorkingPairValue = hand2Info.cardValues[1]
  IF hand2WorkingPairValue EQUALS WILD_VALUE
    hand2WorkingPairValue = ACE_VALUE

  IF (hand1WorkingPairValue > hand2WorkingPairValue)
    RETURN 0 (hand 1's lower-ranking pair wins)
  ELSE IF (hand1WorkingPairValue < hand2WorkingPairValue)
    RETURN 1 (hand 2's lower-ranking pair wins)
  END

  RETURN -1 (both pairs in both hands are equally ranked)
}

The ComparePairs is similar to past ones we’ve written, except the main difference her is, we’re comparing two pairs instead of one. Also, this is why sorting the values in the info.cardValues array in descending order (highest to lowest) is so important.

As you can see, when comparing the higher-ranking pairs of both hands we use cardValues[0] from both hands’ info object. Then if they are equal, we compare the lower-ranking pairs using cardValues[1].

We also do the usual replacing of wild values with aces if the value of a pair is a wild.

Comparing The Kickers

It’s down to the final stretch. Both hands are neck and neck so far, and it’s come down to that final x-factor card for a possible tie-breaker.

CompareKickers
CompareKickers = function(hand1, hand1Info, hand2, hand2Info) {
  SET hand1Kickers = GetKickers(hand1, hand1Info)
  SET hand2Kickers = GetKickers(hand2, hand2Info)
  SET winningPlayerIndex = CardMatchUtils.CompareHands(hand1Kickers, hand2Kickers)
  RETURN winningPlayerIndex
}

This function gets the kicker card. To do this, you exclude from the hand, all other cards that make up both pairs. This happens inside the GetKickers function.

GetKickers
GetKickers = function(hand, info) {
  SET valuesToExclude to an empty array [ ]

  (set the higher-ranking pair of cards to be excluded)
  SET pairValue to info.cardValues[0]
  IF the number of cards in the hand with the value of pairValue EQUALS 2
    add pairValue to the valuesToExclude array
  ELSE IF the number of wild cards in the hand EQUALS 2
    add CardValues.wild to the valuesToExclude array
  ELSE
    add both, pairValue and CardValues.wild to the valuesToExclude array
  END

  (set the lower-ranking pair of cards to be excluded)
  SET pairValue to info.cardValues[1]
  IF the number of cards in the hand with the value of pairValue EQUALS 2
    add pairValue to the valuesToExclude array
  ELSE IF the number of wild cards in the hand EQUALS 2
    add CardValues.wild to the valuesToExclude array
  ELSE
    add both, pairValue and CardValues.wild to the valuesToExclude array
  END

  SET kickers to CardMatchUtils.BuildHandExcludingValues(hand, valuesToExclude, 4)
  RETURN kickers
}

This function will exclude all cards found in pairs, leaving only one card remaining. Even though CardMatchUtils.BuildHandExcludingValues returns a hand (an array of Card objects), the array will always contain just one Card in it.

Now that you have the kickers in both hands, you can compare those cards. Since it’s only one card for each, you could just write a straight up comparison, and return the appropriate index depending on the result.

However, I think it’s still better to write:
SET winningPlayerIndex = CardMatchUtils.CompareHands(hand1Kickers, hand2Kickers)
because we already have that comparison code written, and it’ll already return the appropriate index for us, leaving the code here cleaner. ๐Ÿ˜‰

Conclusion

Whew! This one was pretty meticulous just to compare two hands of two-pairs to see which one won! But I think you’ll be pleased with the result once it’s all working.

Compare Your Own Hands

You can use the controls below to build your own hands and compare hands of two pairs. Have some fun playing around with it, and if you find an issue, please let me know!


Player 1

Result:

Player 2

Result:

Player 3

Result:

Who Won:

If you have any questions about anything in this article, please let me know at cartrell@gameplaycoder.com.

Thanks and take care,

– C. out.

How to Code Poker Hands – Two Pair

Hey! What’s up.

Today, we’ll be resuming in the mini-series of writing code that can tell what kind of poker hand a player has. And the poker hand we’re covering is a two pair.

  • Pair (jacks or higher only)
  • Two pair
  • Three of a kind
  • Straight
  • Flush
  • Full house
  • Four of a kind
  • Straight flush (a non-ace-high straight flush)
  • Royal flush (an ace-high straight flush)

A two pair is a hand that has two cards of one value, two more cards of another value, and a third card whose value is different than the first four. Here is an example the a two pair hand:


We have a pair of kings and sixes.
Setup

If you’d like to see the first article, coding a pair of Jacks or higher, you can check that out here. There, you’ll also a detailed description of the data structures used. But here is a quick rundown of those data structures:

Card values
CardValues = {
  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,
  wild: 100
};
Card suits
CardSuits = {
  hearts: 1,
  diamonds: 2,
  clubs: 3,
  spades: 4
};
Card
Card = function(value, suit) {
  this.value = value;
  this.suit = suit;
};
Hand

And a hand is an array of Card objects:

var hand = [
  new Card([card value 1], [card suit 1]),
  new Card([card value 2], [card suit 2]),
  ...
  new Card([card value 5], [card suit 5])
];
Writing The Code To Identify A Two Pair

When looking for a two pair, it’s also very helpful if we first sort the cards by their value (rank), in descending order. We previously defined a “utilities” file, CardMatchUtils.js, and added a function to it called, CardMatchUtils.SortCardsByDescendingValue, to help with that.

We’re also using the “wild card”, which is a card that can assume the value of any card. So, the following hand would also qualify as a two pair:

In this image, we have a pair of sixes, and because we have a wild card, we take the highest non-paired card, in this case a king, and pair the wild with that. So, we have a pair of kings.

The main function of our pseudocode looks like this:

TwoPair
TwoPair = FUNCTION(hand) {
  SORT the hand by descending card value and store in a variable called sortedHand
  SET wildsInfo to an empty object
  ADD a PROPERTY numWilds to wildsInfo and set it to 0
  ADD a PROPERTY startIndex to wildsInfo and set it to 0
  
  IF CardsHaveSameValue(sortedHand, 2, wildsInfo) AND
  CardsHaveSameValue(sortedHand, 2, wildsInfo)
    //we have two pairs!
    RETURN TRUE 
    
  //no two pair in this hand
  RETURN FALSE
}

That’s itโ€ฆ not so fast! What’s this CardsHaveSameValue function we’ve never seen before? ๐Ÿค”

This is a new utility to our CardMatchUtils.js file. Let’s officially call this CardMatchUtils.DoCardsHaveSameValue. This function will determine if a hand has at a certain number of cards that have the same arbitrary value.

This function accepts three parameters:

  • sortedHand – Array of Card objects that are already sorted in descending value.
  • numToMatch – An integer that indicates how many cards whose value we are looking to match. In our case, it’s two.
  • wildsInfo – An object that will allow us to save data for subsequent calls to this DoCardsHaveSameValue function. From our code above, we called CardsHaveSameValue twice, passing in wildsInfo each time. The first call needs to save certain intermittent data so the next call can resume where the first one left off. The wildsInfo parameter has two properties:
    • numWilds – The number of wild cards available for use as substitutes.
    • startIndex – The index of the sortedHand array on which DoCardsHaveSameValue starts when it checks each card in the hand.

The wildsInfo paramater is only needed if your game supports wild cards. Otherwise, you can set it to null (or don’t specify it, if the programming language you’re using supports some form of optional arguments like JavaScript or C#).

CardMatchUtils.DoCardsHaveSameValue will return true if the specified number of cards have the same value, or false otherwise.

DoCardsHaveSameValue
CardMatchUtils.DoCardsHaveSameValue = function(sortedHand, numToMatch, wildsInfo) {
  SET numWilds to 0
  SET startIndex to 0
  
  IF wildsInfo is specified
    SET numWilds to wildsInfo.numWilds
    IF numWilds is 0
      count the number of wild cards in the hand, and set this value to numWilds
    END IF
    SET startIndex to wildsInfo.startIndex
  ELSE
    count the number of wild cards in the hand, and set this value to numWilds
  END IF
  
  SET maxIndex to sortedHand.length - numWilds - 1
  SET baseCardValue to 0
  SET numMatched to 0
  
  LOOP through each card in the sortedHand array, starting at index startIndex
    IF it's the first card in the loop
      //first card starts off the number of matches with a base card value
      SET baseCardValue to the card's value
      SET numMatched to 1
      CONTINUE with next card in the loop
    END IF
    
    IF the baseCardValue EQUALS the card's value
      //this card's value matches the base card value
      ADD 1 to the current value of numMatched
      
      IF numMatched EQUALS numToMatch
        //total number of matched cards found - success
        IF wildsInfo is specified
          SET PROPERTY wildsInfo.numWilds to numWilds
          SET PROPERTY wildsInfo.startIndex to the current loop index + 1
        END IF
        RETURN TRUE
      END IF
      
      //still need to match more cards for the base card value
      CONTINUE with next card in the loop
    END IF
    
    //This card's value does not match the base card value. Check if there are enough wilds that can satisfy the match.
    
    IF numMatched + numWilds is GREATER THAN OR EQUALS numToMatch
      //there are enough wilds that can satisfy the base card value - success
    
      //deduct the number of wilds used to satisfy the base card value from the current number of wild cards
      SET numberOfWildsToDeduct to numToMatch - numMatched
      DEDUCT numberOfWildsToDeduct from numWilds
      
      //update the wilds info
      IF wildsInfo is specified
        SET PROPERTY wildsInfo.numWilds to numWilds
        SET PROPERTY wildsInfo.startIndex to the current loop index
      END IF
      
      RETURN TRUE
    END IF
    
    //If we arrive here, there are not enough wild cards to satisfy the base card value.
    
    //start a new base card value with the current card that did not match
    SET baseCardValue to the value of the card
    
    IF the card is a wild card
      //the base card value can't be a wild card - abort the for loop
      END LOOP
    END IF
    
    SET numMatched to 1
  END LOOP
  
  //unable to satisfy a match - however, one last attempt, if there are remaining wilds, check if number of matched cards on the last loop + num wilds satify
  IF numMatched + numWilds GREATER THAN OR EQUALS numToMatch
    //there are enough wilds that can satisfy the base card value - success!
    
    //deduct the number of wilds used to satisfy the base card value from the current number of wild cards
    SET numberOfWildsToDeduct to numToMatch - numMatched
    DEDUCT numberOfWildsToDeduct from numWilds
    
    //update the wilds info
    IF wildsInfo is specified
      SET PROPERTY wildsInfo.numWilds to numWilds
      SET PROPERTY wildsInfo.startIndex to the current loop index
    END IF
    
    RETURN TRUE
  END IF
    
  //if we arrive here, we were unable to satisfy a match
  RETURN FALSE
}

You can see that if wildsInfo is specified, its properties are updated for subsequent calls to CardMatchUtils.DoCardsHaveSameValue.

Now, let’s have another look at our previous hand with a wild card in it:

We first sort the cards by descending value, so the sorted hand looks like:

The wild cards are always sorted last.

Note: The order of cards by is are arbitrary in this case. The 6c and 6h cards could have been swapped.

Recall that of TwoPair function calls CardMatchUtils.DoCardsHaveSameValue twice, specifying the samewildsInfo parameter each time.

The first time it’s called, the pair of sixes was found. When CardMatchUtils.DoCardsHaveSameValue completes, it will return true, because it found a pair of kings. When the code doesn’t find a match, it will first try to use as many wilds available to satisy the match. In this hand, there is one wild, so it was used. The wildsInfo object was modified as such:

{
  numWilds => 0
  startIndex => 1
}

The next time CardMatchUtils.DoCardsHaveSameValue is called, instead of starting at the first index (index 0, the KH) in the array, it will start at index 1, the six of clubs. It will find two cards of the same value, the 6C, and 6H, and return true. Since both calls to CardMatchUtils.DoCardsHaveSameValue returned true, this hand does indeed contain two pairs.

If you have any questions, contact me by using the contact form here, or you can e-mail me directly at cartrell@gameplaycoder.com.

And of course, if you have a card game you need help coding, get in touch with me, and let’s talk!

That’s all for now. In the next article, we’ll go over the poker hand, three of a kind.

Thanks, and I’ll talk to you next time. Take care,

– C. out.