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.