It’s been pretty quiet lately here on GameplayCoder, but I’ve also been busy behind the scenes learning new skills for more games to add to my portfolio.
Poker Game
Having finished up the card-matching and hand-comparing techniques for poker, the next project will involve coding an actual poker (Texas Hold’em) game.
As for implementing the rules for poker itself, I found a useful article on 888poker that goes over basics, terminology, and flow of the game. There is also this game available from 24/7 Free Poker, which I’ve been playing to help further understand the game/
But I want it to be a multiplayer game (as well as single-player vs AI), and it’s the multiplayer functionality that will prove most challenging.
So, I’ve been taking a course over on Zenva called MMORPG Academy, which teaches you how to build a multiplayer game using various technologies, and middlewares, including but not limited to:
The only tool in this list I did not use was Docker, because it requires virtualization to run, and if your operating system is Windows 10 Home, you’re pretty much outta luck. Of all the suggestions I’ve tried around the net, none of them worked, and I wasn’t about to upgrade to Pro just for Docker. Besides, you don’t really need it to complete this course anyway.
Everything except Phaser and JavaScript on that list was completely new to me. ๐ So, I’m taking in a lot of new material in this course. But as Tony Stark himself said,
Flash To HTML5 Game Conversion
According to my data, an article I wrote, Converting a Flash Game To HTML5, by far, has received the most views.
After looking at these numbers, I’m like:
So I will be revisiting this topic by converting another Flash game I coded for a previous client, called Blasteroids. This is a remake of Atari’s Asteroids.
If you’d like to play the Flash game I coded, you can play it on my old portfolio site here. Otherwise, if you can’t (or won’t) be bothered with Flash, you can watch this video of my gameplay – and epic fails. ๐
Thanks for being a reader of this blog, and stay tuned. There’s more to come!
When you have two poker hands, and both are straight flushes, this article will show you the code that compares them to find which one wins.
A previous article for poker hands demonstrated how to compare a hand to determine if it was straight flush (the article also covered a royal flush as well). A straight flush is a hand where all the cards are in sequential order, and they all have the same suit. This hand is a straight flush:
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 Fours Of Kinds
When two hands that are both a straight flush, the GetWinningHand function will call the FindWinnerStraightFlush function that compares the two hands.
Note: As it turns out, comparing two straight flush hands is the same as comparing two straight hands! The only addition is that you have to make sure all the cards are the same suit.
The only code featured in this article are the functions specific to comparing straight flushes. To see the concepts and code for comparing two straights, see this article.
FindWinnerStraightFlush
FindWinnerStraightFlush = function(hand1, hand2) {
SET workingHand1 = CardMatchUtils.SortCardsByDescendingValue(hand1);
SET hand1Info to an empty object { }
CardMatchUtils.AreCardsStraight(workingHand1, hand1Info)
SET workingHand1 = WildsAssumeValues(workingHand1, hand1Info)
SET sortedHand2 = CardMatchUtils.SortCardsByDescendingValue(hand2);
SET hand2Info to an empty object { }
CardMatchUtils.AreCardsStraight(workingHand2, hand2Info)
SET workingHand2 = WildsAssumeValues(workingHand2, hand2Info)
SET winningPlayerIndex = CardMatchUtils.CompareHands(workingHand1, workingHand2)
RETURN winningPlayerIndex
}
WildsAssumeValues
WildsAssumeValues = function(hand, info) {
SET index to 0
WHILE index IS LESS THAN number of cards in the hand (for example, "hand.length")
SET card = hand[index] (get the nth card in hand)
IF the card is a wild (card.value EQUALS CardValues.wild)
SET the card value to the last value in the info.cardValues array
REMOVE the last card value from the info.cardValues array (info.cardValues.pop())
END
SET index = index + 1
END
SET sortedHand to CardMatchUtils.SortCardsByDescendingValue(hand)
RETURN sortedHand
}
Compare Your Own Hands
You can use the controls below to build your own hands and compare fours of kinds. Have fun playing around with it!
Player 1
Card 1
Card 2
Card 3
Card 4
Card 5
Result:
Player 2
Card 1
Card 2
Card 3
Card 4
Card 5
Result:
Player 3
Card 1
Card 2
Card 3
Card 4
Card 5
Result:
Who Won:
If you have any questions about anything in this article, please let me know at cartrell@gameplaycoder.com.
When you have two poker hands, and both are a four of a kind, how can you determine which one ranks higher? In this article, you’ll learn how to code a solution.
A previous article for poker hands demonstrated how to compare a hand to determine if it was four of a kind. A four of a kind is hand where four of the cards are the same value, and the remaining card is a different value. It’s like a three of a kind, but instead of matching three cards, it matches four. Hereโs an example of a four of a kind:
Also, the comparison process is very similar to a comparing threes of kinds:
Compare the values of the quadruplet (the four cards that have the same value).
If those values are equal, compare the values of other the kickers, which is the card that has the other value.
If no kicker breaks the tie, and all cards have been compared, then both hands are equal.
Let’s look at some examples:
Hand 1
Hand 2
Hand 1 has a quad value of 5, while hand 2 has a quad value of 3. Since 5 is greater than 3, hand 1 is the higher four of a kind.
If the quad values of both hands are the same, then you compare the kicker card. Check this out:
Hand 1
Hand 2
Both hands had a quad value of queen. Hand 1 has a kicker value of king, while hand 2’s kicker value is ace. Ace beats king, so hand 2 is the winner here.
And one more thing before we get into the code – the wild cards (:
But handling wild cards in comparing a four of a kind is similar to that of a three of a kind. Take these hands:
Hand 1
Hand 2
In hand 1, the wild card is swapped for a 2 to form a four of a kind. The kicker value is a queen. For hand 2, it already has a four of a kind from the twos, so you can use the wild card to substitute the highest possible value, an ace.
When comparing both hands, hand 2 wins, because it has the higher kicker value (ace winning over queen).
Note: In hand 1, you could’ve substituted also the wild with the highest possible value, ace. But then, it would no not form a four of a kind, but a three of a kind. You also could’ve substituted it with another queen to form a full house, twos over queens, but a full house ranks lower than a four of a kind. So, substituting the wild for as a two produces the highest possible hand.
On a side note, in hand 2, you could’ve substituted the wild as a two, forming a five of a kind, which ranks higher than a four of a kind. However, we won’t be covering fives of kinds in this series. I’ll leave it as a challenge to you, should you accept it (: If you’re interested, you can learn a little more about a five of a kind here.
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 Fours Of Kinds
When two hands are both a three of a kind, the GetWinningHand function will call a function that compares two hands of said poker hand.
In this case, GetWinningHand function will eventually call FindWinnerFourOfAKind (shown below) to compare the hands. This function 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 indicate a draw). The pseudocode below starts by comparing the values of the pairs first, then comparing the kickers if necessary.
FindWinnerFourOfAKind
FindWinnerFourOfAKind = function(hand1, hand2) {
sortedHand1 = CardMatchUtils.SortCardsByDescendingValue(hand1);
SET hand1Info to an empty object { }
CardMatchUtils.DoCardsHaveSameValue(hand1, 4, hand1Info);
sortedHand2 = CardMatchUtils.SortCardsByDescendingValue(hand2);
SET hand2Info to an empty object { }
CardMatchUtils.DoCardsHaveSameValue(hand2, 4, hand2Info);
SET winningIndex = CompareQuads(hand1, hand1Info, hand2, hand2Info);
IF (winningIndex NOT EQUAL TO -1)
RETURN winningIndex (one hand's quad outranks the other hand's, and no further checking is necessary)
END
(both hands have the same ranking quad, now compare the kickers of both hands)
SET winningIndex = CompareKickers(hand1, hand1Info, hand2, hand2Info);
RETURN winningIndex;
}
Like most poker hand matching and comparing functions, you’ll need to first sort the cards in descending order of value (highest to lowest) before processing. This helps tremendously in the code. Yeah, you and I could just “look” at a couple hands and see the winner, but code? Not so much. ๐
If you already read the article for comparing threes of kinds, this function looks very similar to FindWinnerThreeKind!
(Psst, here’s the big secret! ๐ฑโ๐ค You catch a break with comparing fours of kinds. It’s mostly a copy-paste job, changing threes to fours, and replacing “trios” with “quads”)
Comparing The Quadruplets
In the FindWinnerFourOfAKind function, the code above sets the hands up for comparing their quadruplets. It then sorts the cards or descending order by card value. Next, it uses the DoCardsHaveSameValue function to get the four cards in the hand that make the quad, as well as determine the quad’s value.
CompareQuads
CompareQuads = function(hand1, hand1Info, hand2, hand2Info) {
SET hand1WorkingQuadValue = hand1Info.cardValues[0]
IF (CardMatchUtils.CountCardsByValue(hand1, WILD_VALUE) GREATER OR EQUALS 4)
hand1WorkingPairValue = ACE_VALUE
END
SET hand2WorkingQuadValue = hand2Info.cardValues[0]
IF (CardMatchUtils.CountCardsByValue(hand2, WILD_VALUE) GREATER OR EQUALS 4)
hand2WorkingQuadValue = ACE_VALUE
END
IF (hand1WorkingQuadValue > hand2WorkingQuadValue)
RETURN 0 (hand 1 has the higher ranking quad)
ELSE IF (hand1WorkingQuadValue < hand2WorkingQuadValue)
RETURN 1 (hand 2 has the higher ranking quad)
END
RETURN -1 (both hands' quads have the same value)
}
This function is very similar to the CompareTrios function in our recent article for comparing threes of kinds, except instead of dealing with three cards, we’re dealing with four. If youโd like details on the workings of that function, please check here.
Comparing The Kickers
If the quads of both hands have the same value, then youโll need to compare the final card in each hand, its kicker.
Like you did when comparing the kickers with previous poker hands, when comparing the kickers, you first remove the quads from both hands so you’re left with the remaining kicker. You can use the CardMatchUtils.BuildHandExcludingValues function to remove the quad.
GetKickers
GetKickers = function(hand, info) {
(get the value of the cards that form the quad)
SET quadCardValue = info.cardValues[0]
(count the number of cards in the hand that match the quad card value)
SET numQuadValueCards = CardMatchUtils.CountCardsByValue(hand, quadCardValue)
(if there are at least as many quad value cards as there are non-kicker cards, specify the quad card value to the values of cards to exclude)
SET numNonKickerCards = 4
IF numQuadValueCards >= numNonKickerCards
SET valuesToExclude = quadCardValue
ELSE {
(otherwise, if there are at least as many wild cards as there are non-kicker cards, add the wild card value to the values of cards to exclude)
SET numWildCards = CardMatchUtils.CountCardsByValue(hand, CardValues.WILD)
IF numWildCards >= numNonKickerCards
SET valuesToExclude = CardValues.WILD
ELSE
(finally, specify BOTH, the quad card value and the wild card value as the values of cards to exclude)
SET valuesToExclude = [ CardValues.WILD, quadCardValue ]
END
}
(create the temporary kickers hand by excluding the specified values and returning the rest)
SET handOfKickers = CardMatchUtils.BuildHandExcludingValues(hand, valuesToExclude, numNonKickerCards)
(finally, sort the kickers hand in descending order, with wilds as the highest value)
handOfKickers = CardMatchUtils.SortCardsByDescendingValueHighWilds(handOfKickers)
RETURN handOfKickers
}
In the GetKickers above, the info object is the same one used in FindWinnerFourKind. It’s either the hand1Info or hand2Info object, depending on which hand you’re getting the kickers from.
There are three situations in GetKickers that determine which values of cards to exclude as kickers.
The first is the simplest. Itโs the quad card value used to form the four of a kind. Cards of this value obviously canโt be the kickers. This means they’ll be excluded, leaving the remaining card as the kicker.
The second situation is a hand that contains at least four wilds cards. These cards can assume the highest non-wild value, which is an ace. So the four wilds would form the four of a kind, using an ace as the quad card value. So the wild card value itself would be excluded from the hand of kickers.
Finally, the hand doesnโt have four cards with the same value, but it does contain one of the following combinations:
One wild and a triplet
Two wilds and a pair
Three wilds and the higher non-kicker of the remaining two cards
Note: When excluding cards, you’re always excluding exactly four cards (the number of non-kicker cards).
Those wilds will assume the value of the whatever the quad value is, forming the four of a kind. In this situation, you want to exclude both values of both, the wild card, and the quad card value.
The GetKickers function from above helps with this.
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
}
The CardMatchUtils.CompareHands function is the same one we used here.
The CompareKickers will return 0 if hand1 has the better kickers, 1 if hand2 has the better kickers, or -1 if both hands are the same rank.
That’s pretty much it! ๐
Compare Your Own Hands
You can use the controls below to build your own hands and compare fours of kinds. Have fun playing around with it!
Player 1
Card 1
Card 2
Card 3
Card 4
Card 5
Result:
Player 2
Card 1
Card 2
Card 3
Card 4
Card 5
Result:
Player 3
Card 1
Card 2
Card 3
Card 4
Card 5
Result:
Who Won:
If you have any questions about anything in this article, please let me know at cartrell@gameplaycoder.com.
Continuing the series of comparing poker hands of the same rank, this article will show you how to write code to compare two hands that are both a full house.
In a previous article for poker hands, you learned how to write code that checks if a hand is a full house. That is, the hand contains three cards of one value, and two of another, and the suits are not all the same.
Three cards are nines, two cards are fours, and their suits are not uniform.
Comparing a full house looks like this:
Compare the triplets of both hands. Highest triplet wins.
If they are both the same, compare the pairs of both hands. Highest pair wins.
Both hands have equal triplets and pairs. They’re tied.
Getting Triplet And Pair Values
Before we can compare triplets and pairs, we need to get the values of the cards that make up the triplets and pairs.
Let’s first have a look at the cards in hand, because after being sorted in descending value, they’ll have one of two orders.
Note: Make sure that the cards are sorted by card rank in descending order (highest to lowest) first.
First order: You could have – what we’ll call a “3-2” full house – where the higher value is the triplet and the lower value is the pair, as in:
The value of the triplet is 10, and the value of the pair is 3.
Second order: You could have a “2-3” full house, where the pair is the higher value and the triplet is lower.
This time they’re switched. The value of the pair is 10, and the value of the triplet is 3.
To determine the triplet and pair values, compare the values of second and third card of the hand. ๐ก
In the 3-2 full house, 10โฆ 10โฃ 10โ 3โฅ 3โฆ, the values of the second and third card will be the same. In this case, they’re both 10. That means the value pf the triplet is 3. From this, the pair starts on the fourth card, so the value of the pair is the value of that fourth card (in this case, 2).
In the 2-3 full house, 10โฆ 10โฃ 3โฅ 3โฆ 3โ , the values of the second and third card will be different. Here, the value of the triplet is 2, and the value of the pair is 10.
Now that you know the values of the triplets, you can compare them. In the example we’ve been using 10 > 3, so the 3-2 hand wins over the 2-3 hand.
And if the values of the triplets were the same, then you’d compare the values of the pairs to determine the higher hand. And if the pairs were the same, both hands are of equal rank.
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 Full Houses
When both hands are full houses, the GetWinningPlayerId function will eventually call a the FindWinnerFullHouse function that compares them to determine which one wins.
FindWinnerFullHouse
FindWinnerFullHouse = FUNCTION(hand1, hand2)
SET workingHand1 = CardMatchUtils.SortCardsByDescendingValue(hand1)
SET workingHand2 = CardMatchUtils.SortCardsByDescendingValue(hand2)
SET trioPairValues1 = GetTrioPairValues(workingHand1)
SET trioPairValues2 = GetTrioPairValues(workingHand2)
SET trioValue1 = trioPairValues1[0]
SET trioValue2 = trioPairValues2[0]
IF (trioValue1 > trioValue2)
RETURN 0
ELSE IF (trioValue1 < trioValue2)
RETURN 1
END
SET pairValue1 = trioPairValues1[1]
SET pairValue2 = trioPairValues2[1]
IF (pairValue1 > pairValue2)
RETURN 0
ELSE IF (pairValue1 < pairValue2)
RETURN 1
END
RETURN -1
END
GetTrioPairValues
GetTrioPairValues = FUNCTION(hand)
SET secondCardValue = hand[1].value;
SET thirdCardValue = hand[2].value;
IF secondCardValue EQUALS thirdCardValue
SET fourthCardValue = hand[3].value;
RETURN [ secondCardValue, fourthCardValue ]
END
RETURN [ thirdCardValue, secondCardValue ]
END
In the code above, first we sort both hands by card rank in descending order. Next, we call a new function, GetTrioPairValues, which will tell us the values of the pairs and triplets of both hands. The value that GetTrioPairValues returns is an array that contains two elements: first is the value of the triplet, second is the value of the pair.
Next, the code compares the values of the triplets. If a winner is found, it returns the winning player index (0 for the hand 1, or 1 for hand 2). Otherwise, it compare pairs, and again returning the winning player index if a winner is found. And finally, if the pairs are equal, it returns -1, meaning both hands are evenly matched.
That’s it! This one was easy! ๐
.. Whooaaa, hold on a minute chief. What about the wild cards? ๐
Ugh! Them damn wild cards again! Shit! ๐ Well, we’ll handle those next.
Comparing Two Full House Hands With Wild Cards
If a hand has wild cards, the would assume values that would create the best full house possible. If one or more wild cards are in the hand, the above logic, about comparing the second and third cards in the hand, will not work, because the hand won’t have both a triplet and a pair.
We can restore that logic by first replacing the wilds with actual card values. The first step to this is using our handy CardMatchUtils.DoCardsHaveSameValue function.
We’ve used this function many times before. It will tell us if a card with a certain value appears in the hand a specified number of times. Also, if wild cards are in the hand, they can assume said card’s value in order to help satisfy the count. The function returns true if the card was found in the hand the specified number of times. Lastly, the function tracks the values of those cards that match the specified count.
We’ve made some updates to the function since it was first introduced. And we’ll make some new changes here to accommodate wild cards.
DoCardsHaveSameValue
CardMatchUtils.DoCardsHaveSameValue = FUNCTION(sortedHand, numToMatch, wildsInfo)
SET numWilds to 0
SET startIndex to 0
SET cardValues to empty array []
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
SET startIndex to wildsInfo.startIndex
SET cardValues to wildsInfo.cardValues
ELSE
count the number of wild cards in the hand, and set this value to numWilds
END
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
IF the card is a wild card
//first card is a wild card - the only way the first card would be a wild is if all cards
// starting at the start index are wilds (assuming cards are already sorted in descending
// value order, with wilds at the end)
//the hand must contain at least as many wilds as the requested number of cards to match
IF (u_numWilds LESS THAN u_numToMatch)
RETURN FALSE
END
IF wildsInfo is specified
SET PROPERTY wildsInfo.numWilds to numWilds - numToMatch
SET PROPERTY wildsInfo.startIndex to [index of card within loop] + numToMatch;
ADD card's value into cardValues array
SET PROPERTY wildsInfo.cardValues to cardValues
END
RETURN TRUE
ELSE
//first card starts off the number of matches with a base card value
SET baseCardValue to the card's value
END
SET numMatched to 1
CONTINUE with next card in the loop
END
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
ADD card's value into cardValues array
SET PROPERTY wildsInfo.cardValues to cardValues
END
RETURN TRUE
END
//still need to match more cards for the base card value
CONTINUE with next card in the loop
END
//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
ADD baseCardValue into cardValues array
SET PROPERTY wildsInfo.cardValues to cardValues
END
RETURN TRUE
END
//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
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
IF baseCardValue NOT EQUAL 0
ADD baseCardValue value into cardValues array
ELSE
ADD wild card value (CardValues.wild) into cardValues array
END
SET PROPERTY wildsInfo.cardValues to cardValues
END
RETURN TRUE
END
//if we arrive here, we were unable to satisfy a match
RETURN FALSE
END
In a nutshell, this function now handles what happens if it encounters a wild card as the first card it checks, and that if only wild cards were processed, the cardValues array will specify the wild card value to let us know.
Note: Just like when you determined if a card was a full house, you’ll need to call the CardMatchUtils.DoCardsHaveSameValue function twice, once to look for the triplet, and again for the pair, as in a 3-2 full house. If you don’t get successful calls both times, you’ll then need to check for a 2-3 full house. You can find details of this on the original full house-matching article here.
If you’re checking for a 3-2 full house, you’d write something like this:
SET info to an empty object { };
IF CardMatchUtils.DoCardsHaveSameValue(hand, 3, info) AND CardMatchUtils.DoCardsHaveSameValue(hand, 2, info))
(we have a 3-2 full house)
END
And for a 2-3 full house:
SET info to an empty object { };
IF CardMatchUtils.DoCardsHaveSameValue(hand, 2, info) AND CardMatchUtils.DoCardsHaveSameValue(hand, 3, info))
(we have a 2-3 full house)
END
Here are five examples of some hands encountered what the cardValues array will include, and the intended resulting hands are.
Example 1 Hand: 8-8-7-7-w (“w” is a wild card, and suits don’t matter in a full house) Becomes: 8-8-(8)-7-7 The cardValues array would be [8, 7] This would end up being a 3-2 full house, as the wild assumes the third eight.
Example 2 Hand: 8-8-7-w-w Becomes: 8-8-(8)-7-(7) cardValues: [8, 7] he first DoCardsHaveSameValue call will substitute one of the wilds as the eight, satisfying the triplet. On the second call, the other wild is used to satisfy a pair of sevens, qualifying as a 3-2 full house.
Example 3 Hand: 8-7-w-w-w Becomes: 8-(8)-(8)-7-(7) cardValues: [8, 7] imilar to the last example, but the first DoCardsHaveSameValue substituted two eights to satisfy the triplet.
Example 4 Hand: 8-w-w-w-w Becomes: (A)-(A)-(A)-8-(8) cardValues: [8, w] A little tricky one here (: Normally, this hand would become 8-(8)-(8)-(A)-(A), because the eight was encountered first, so and there are enough wilds to satisfy the triplet for a 3-2. However, 8-8-8-A-A is not the best hand that can be formed, because we also have enough wilds to form triple aces (which is the highest triplet possible).
That’s where having the DoCardsHaveSameValue function put a “wild card value” in the cardValues array, as you can see in the second call. Later on in this article, we’ll deal with this when we start replacing wilds with actual card values. Hang tight for now ๐
Example 5 Hand: w-w-w-w-w Becomes: (A)-(A)-(A)-(K)-(K) cardValues: [w, w] Wow! ๐ฎ The DoCardsHaveSameValue function gives us two wild card values in its cardValues array for a 3-2. With all wilds, we substitute the highest cards possible: a trio of aces and a pair of kings. Like the last example, there’s a bit of substitution going on here, in both the hand, and the card values, which I’ll show you how to handle in this article.
Setting Up The cardValues For Substitutions Of Wilds
Now that we have a triplet and pair value in the cardValues array, we can begin handling the situations where wilds are in the hand.
But first, if the cardValues array itself contains wild cards, as in examples 4 and 5, we must first replace those with non-wild card values before we can replace those in the hand.
There are two steps to do this:
Start with the highest value card, ace, and replace one wild in the cardValues with that.
If the other value in the array is also a wild, replace that one with a king.
Sort the contents of the new cardValues in descending order of value.
So, let’s have a look at example 4. cardValues: [8, w] We’d replace the wild with an ace, and the array looks like: [8, A] Then after sorting in descending order of value it now looks like: [A, 8]
In example 5, we had cardValues: [w, w] We’d replace the wild with an ace, and the array looks like: [A, w] Then, replace the second wild with a king to get [A, K] They are already properly sorted.
Some code for this function, looks like:
WildsAssumeInfoCardValues
WildsAssumeInfoCardValues = FUNCTION(cardValues)
SET replaceValue to CardValues.ace
IF cardValues[0] EQUALS CardValues.wild
SET cardValues[0] to replaceValue
SET replaceValue to CardValues.king (or subtract 1)
END
IF cardValues[1] EQUALS CardValues.wild
SET cardValues[1] to replaceValue
END
sort cardValues in descending order
END
What this WildsAssumeInfoCardValues does is start with a “replacing value” of ace. Then, every time it encounters a wild value in the cardValues array, it replaces that value with the value of replaceValue. If it’s the first card in the array, it also sets the replacing value to king, so that if the second card is also a wild, it would be replaced with a king instead of an ace.
Replacing Wilds In The Hand
Nooooww!
We’re finally ready to replace the wilds in the hand with values from the cardValues array!
What we’re doing here is first starting with the first value in the cardValues array (triplet), and replace, up to the number of replacements necessary, wilds with that card value.
Then, we do the same for the second value in the cardValues array for the pair.
Let’s dive in. ๐
WildsAssumeCardValues
WildsAssumeCardValues = FUNCTION(hand, cardValues)
SET numWilds TO CardMatchUtils.CountCardsByValue(hand, CardValues.wild)
(handle triplet)
SET cardValue TO cardValues[0]
SET numCardsWithValue TO CardMatchUtils.CountCardsByValue(hand, cardValue)
SET numCardsToMatch TO 3
SET numWildsToReplace TO numCardsToMatch - numCardsWithValue
IF numWildsToReplace LESS THAN OR EQUAL TO 0
(skip the rest of handling triplet and move on to "handle pair"
END
SET cards TO (make a copy of the cards in the hand)
FOR EACH card IN cards
IF the card is a wild card
replace that value of the card with cardValue
decrease numWilds by 1
IF numWilds EQUALS 0
RETURN (we're done; no more wilds to replace)
END
END
END
(handle pair)
SET cardValue TO cardValues[1]
SET numCardsWithValue TO CardMatchUtils.CountCardsByValue(hand, cardValue)
SET numCardsToMatch TO 2
SET numWildsToReplace TO numCardsToMatch - numCardsWithValue
IF numWildsToReplace LESS THAN OR EQUAL TO 0
RETURN (we're done; no wilds to replace)
END
SET cards TO (make a copy of the cards in the hand)
FOR EACH card IN cards
IF the card is a wild card
replace that value of the card with cardValue
decrease numWilds by 1
IF numWilds EQUALS 0
RETURN (we're done; no mre wilds to replace)
END
END
END
sort cards by in order of descending card value
RETURN cards
END
This function replaces wilds in the hand with values specified in the cardValues array, until it runs out of wilds in the hand. Triplets are handled first, getting the higher value of the cardValues array. Then if there are any wilds left, the pair is handled.
Coming Full Circle
If you’re still with me, than great job getting this far! (muscle arm emote)
Now that we’ve removed all wilds in the hand, you can go back and use the GetTrioPairValues to get the values of the triplets and pairs, and finally compare triplets and pairs to determine which full house pair wins.
You’ve reached the end for comparing full houses! No, for real this time, that’s it. ๐
Compare Your Own Hands
You can use the controls below to build your own hands and compare full houses. Have fun playing around with it!
Player 1
Card 1
Card 2
Card 3
Card 4
Card 5
Result:
Player 2
Card 1
Card 2
Card 3
Card 4
Card 5
Result:
Player 3
Card 1
Card 2
Card 3
Card 4
Card 5
Result:
Who Won:
If you have any questions about anything in this article, please let me know at cartrell@gameplaycoder.com.
If you’re an avid poker player, or even if you’re just starting out, I invite you to check out the poker odds calculator for Texas Hold ’em. With this tool, you can calculate your odds for winning any game. I found a very polished calculator that is available here.
Basic operation of a calculator is adding the cards to your hand and community. It then determines the odds your hand has of winning.
In this article, I’ll cover how you can code a simple poker odds calculator. First, let’s go over how the calculator stores the cards in your hand and the community.
Setup Card Data
A card is the basic data block we’ll be using. We’ll create a simple Card object, that will store the suit and value of each card. You can write it as:
A player’s hand is stored as an array of Card objects. The array has two elements, one for each card. You’d setup that up like this:
Note: If you’d like to see, in detail, the setup for card values, suits, Card objects, and hands, please see this link to an earlier article.
Setup Player and Community Data
The player’s hand and community cards are both defined as arrays, and will contain several Card objects:
var playerHand = [];
var communityCards = [];
Adding Player And Community Cards To Be Played
To add a card to the player’s hand, construct a new Card object, set its value and suit, then add it to the playerHand array. Say you want to add the 4โฃ. You’d write:
var card = new Card(CardValues.four, CardSuits.clubs);
var playerHand = allPlayerHands[0];
playerHand.push(card);
Adding a community card is similar. To add a Qโฆ:
var card = new Card(CardValues.queen, CardSuits.diamonds);
communityCards.push(card);
Evaluating Odds
Now that you have set up the players and cards, you can begin calculating odds.
First, create the scenario you want to evaluate. In the following example, we’ll use four community cards from the flop and turn. Let’s say your hand is 4โฃ 9โฃ, and the community cards are 7โฆ, 5โฃ , Kโฅ, 8โฃ. You’d code this as:
Then, determine the best possible hand for the player using the cards in the player’s hand, and the community cards. You do this by finding how many “outs” you have. An out is an unknown card (in this case, the final river card) that, when added, will give you the best hand.
Next, determine which potential river cards would give you a strong or winning hand (a flush or straight): any 6 (four cards), or 2โฃ, 3โฃ, 7โฃ, 10โฃ, Jโฃ, Qโฃ, Kโฃ, and Aโฃ. So, there are a total of 12 outs.
Note: Writing code to determine the outs themselves, or compare odds for multiple players both go beyond the scope of this article. I may cover them in future articles.
When matching and comparing poker hands, you may find it easier to use a “temporary hand” (a new array) when evaluating numerous combinations of the player’s cards with the community cards. For example, consider this:
var workingHand = [
playerHand[1],
communityCards[0],
communityCards[1],
communityCards[2],
communityCards[3]
];
The above code gives you a working hand of 9โฃ, 7โฆ, 5โฃ, Kโฅ, 8โฃ. You could then perform the various card matching actions on this array, using functions from previous articles, such as sorting ( CardMatchUtils.SortCardsByDescendingValue ), or determining if a hand is a straight ( CardMatchUtils.AreCardsStraight ).
To calculate the percentage you have of getting one of these out cards, you need to factor in the remaining number of cards in the deck, which is 46. A breakdown is:
const MAX_NUM_CARDS_IN_DECK = 52;
var numCardsInPlayerHand = playerHand.length; //2
var numCommunityCards = communityCards.length; //4
var numberOfCardsRemaining = MAX_NUM_CARDS_IN_DECK - numCardsInPlayerHand - numCommunityCards; //52 - 4 - 2 = 46
Of those 46 cards, 12 of them (the outs we found earlier) will give you a strong or winning hand. You can find the percentage of getting one of them with this:
var percentage = 1 - (numberOfCardsRemaining - numOuts) / numberOfCardsRemaining;
In our example, this is 1 – (46 – 12) / 46 = 0.26, or a 26% chance.
If you want to go further and represent this in odds notation (“x to y”), do this calculation:
var odds = 1 / percentage - 1;
Which yields, 1 / 0.26 – 1 = 2.8, or “2.8 : 1”. This means for about every 3 games, you might get a flush or straight.
That’s it for this article! I’ll talk to you next time. Thanks and take care ๐
Continuing the series of comparing poker hands of the same rank, this article will show you how to write code to compare two flushes to see which ranks higher.
In a previous article for poker hands, you saw how to check a hand to determine if a it’s a flush. That is, all five of its cards are the same suit, and their values are not in sequential order.
Each card is diamonds, and they are not all in sequential order.
Comparing two flush hands is a bit easier than the others we’ve covered so far. You need to perform these three steps:
Temporarily replace all wilds with aces.
Sort cards in hand by descending value.
Compare cards in both hands.
And we’ve performed these tasks before, so let’s get started!
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 Flushes
When both hands are flushes, the GetWinningPlayerId function will eventually call a the FindWinnerFlush function that compares them to determine which one wins.
Let’s have a look at that function.
FindWinnerFlush
FindWinnerFlush = function(hand1, hand2) {
SET workingHand1 = CopyHand(hand1)
ReplaceWildsWithAces(workingHand1)
SET workingHand1 = CardMatchUtils.SortCardsByDescendingValue(workingHand1)
SET workingHand2 = CopyHand(hand2)
ReplaceWildsWithAces(workingHand2)
SET workingHand2 = CardMatchUtils.SortCardsByDescendingValue(workingHand2)
SET winningPlayerIndex = CardMatchUtils.CompareHands(workingHand1, workingHand2)
RETURN winningPlayerIndex
}
Let’s go over the three steps in more detail.
STEP 1: Temporarily Replace All Wilds With Aces
First, you want to replace any wild cards in the hand with aces. Although a Flush is a hand where all cards are the same suit, if we’re comparing two flushes, the cards’ values now play a factor. So wilds can be replaced with aces to give the highest possible hand value. Also remember, wilds can assume any suit as well as any value, so the condition of the flush is still met.
Say, you had this hand:
That one wild card would be replaced with an ace:
Note: Wilds, as covered in this series, and for the sake of keeping the pseudo code relatively simple when wilds are involved, have no restrictions on the actual card suits and values they can replace. As you can see in the substitution in the above image, it contains two ad cards. If you’d like more official rulings on wilds, please have a look at this Wiki.
Since the card values are being altered, we don’t want to modify the original hands (hand1 and hand2 from above). So, first, you need to make a copy of the hand. You’ll then do all your work and comparing on this “working hand”.
CopyHand
CopyHand = function(hand) {
SET copyHand = new Array()
FOR EACH card in hand
(create a copy of the card)
SET copyCard = new Card(card.value, card.suit)
(add the copied card to the copy hand)
copyHand.push(copyCard)
END
RETURN copyHand
}
Now that you have a copy of all cards in the hand, let’s have a look at the psuedo code that replaces wilds with aces.
ReplaceWildsWithAces
ReplaceWildsWithAces = function(hand) {
FOR EACH card in hand
IF (card.value EQUALS CardValues.wild)
card.value = CardValues.ace
END
END
}
STEP 2: Sort Cards In Hand By Descending Value
Next, after all the wilds have been replaced with aces, sort the cards in the working hand in order of descending value (highest to lowest). We turn to our hero, CardMatchUtils.SortCardsByDescendingValue! We’ve used this guy many times nowโฆ where would we be without him? I don’t know about you, but I don’t wanna find out! ๐
Step 3: Compare Cards In Both Hands
The final step is comparing the cards in both hands.
Once again, we turn to a highly used function, CardMatchUtils.CompareHands. This function will compare two hands, both are assumed to already be sorted by descending card value. It accepts two parameters, hand1 and hand2. If hand1 has the higher hand, the function returns 0. If hand2 is higher, 1 is returned. Otherwise, -1 is return if both hands are equal.
So compared to other hand-comparing topics, comparing two flush hands is relatively easy. We’ve already written most of the functions used comparing flushes.
Example
Let’s have one example, using the two hands featured at the top of this article. Which one wins? Let’s find out! โ
Hand 2
Hand 2
First, let replace all wilds with aces. Hand 1 has one wild in it, so it now looks like:
The wild assumes both value and suit, and becomes an ace of diamonds.
Hand 2 has no wilds, so we’re done with step 1.
Next, we sort the cards in each hand by value in descending order. The hands now look like:
Hand 1
Hand 2
Finally, compare the cards, starting with the first card in each hand. Both hands have an ace, so move on to the second card.
Hand 1 has a jack, while hand 2 hand a queen. The queen outranks the jack, so hand 2 is the winning flush hand. ๐
That’s it for comparing flushes! Below is a set of controls you can play with to creating and compare your own flush hands.
Compare Your Own Hands
Player 1
Card 1
Card 2
Card 3
Card 4
Card 5
Result:
Player 2
Card 1
Card 2
Card 3
Card 4
Card 5
Result:
Player 3
Card 1
Card 2
Card 3
Card 4
Card 5
Result:
Who Won:
If you have any questions about anything in this article, please let me know at cartrell@gameplaycoder.com.
Continuing the series of comparing poker hands of the same rank, this article will show you how to write code to compare two straights to see which one wins.
In a previous article for poker hands, you saw how to check a hand to determine if a hand was a straight. A straight is a hand where the values of all five cards are in sequential order. Here’s an example of a straight:
From left to right, each card is one less than the last one.
Comparing Straight Hands
When both hands are a straight, it’s very easy to compare the hands. First, sort the cards in order of descending value, meaning from highest to lowest. Next, compare the first card (highest) card from each hand. The hand with the higher card is the hand with the higher-ranking flush. If both cards are equal, then both hands are of equal rank.
Have a look at this example, hand 2 has the higher-ranking flush, since a jack outranks an eight.
Hand 1
Hand 2
This works very well for card values two through ace. But what about dem pesky wild cards? ๐ผ
Comparing Straight Hands With Wild Cards
Wildcards do complicate things a little, but it’s nothing we can’t handle. ๐
Note: You can’t compare straights with wild cards in them, so you have to substitute them for the correct values. Before, when all you were doing was determining if a hand is a straight or not, this was not necessary. However, before you can do a comparison, you need to have all the wilds gone.
When you have wildcards in a straight hand, you can do these three steps:
Substitute card values for any values in between the highest and lowest card to fill out the straight. Use as many wilds as needed to fill out the gap between the highest and lowest card.
If there are any wilds left over, and the highest card is not an ace, substitute one wild with a card value higher than the highest card.
Repeat step 2 until you have replaced a wild card with an ace, or you run out of wilds.
If there are any wilds left over, and the lowest card is not a two, substitute one wild with a card value lower than the lowest card.
Repeat step 3 until you have replaced a wild card with a two, or you run out of wilds.
Some visual examples are always in order. ๐
Example 1
Have a look at this hand:
Following step 1, you can substitute the two wilds with an eight and six, and you end up with:
Note: Remember, in a straight, as long as the hand contains at least two different suits, the suits don’t matter.
Example 2
Let’s try this hand:
Again, following step 1, we substitute wilds in between the highest and lowest values. Here, we’d use one wild and replace it with a nine, and we have:
We’ve one wild remaining, so we move on to step 2, and replace it with one higher than the highest card. So, you’d replace that wild with a queen, finally ending up with:
Example 3
Hey, lemme get another. Thanks, man. Good lookin’ out. ๐ค๐พ๐ค๐พ
Yep. (: If you’re holding these cards:
Step 1: There is no gap in between the queen and jack, so there’s nothing to do here.
Step 2: You can replace two cards higher then the queen, the king and ace. So you’d end up with this:
Step 3: With one wild left over, you replace it with one card lower than the lowest card, which currently is a jack. So, your final hand looks like:
Example 4
One final example. This one’s a bit of a smart-ass hand ๐
You can imagine some dude trying to put in all wilds to break the program. Yeah, well, you got his number, too.
Here, you have no existing card values from which to establish a highest or lowest card. So to make the best possible straight, you can simply replace it with a hand that looks like the previous example’s solution:
However, there is a more programmatic way of doing this other than simply a brute force hard-code, which I’ll show you how.
Because there are no card values, you can establish a “fake” highest and lowest value of “ace + 1”. Since the highest and lowest values are the same, step 1 is skipped. Since your highest value is higher than an ace (somehow, lol), step 2 is skipped.
That leaves step 3, so you start replacing wilds with values lower than the lowest value, which is also “ace + 1”. So the first wild would substitute “ace + 1 – 1” = ace. Then the next substitution is one lower than the lowest value, ace, which is ace – 1 = king.
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 Straights
When both hands are straights, the GetWinningPlayerId function will eventually call the FindWinnerStraight function that compares them to determine which one wins.
First, if either hand contains any wild cards, you’ll need to substitute them using the three steps mentioned above. Once all wilds have been substituted in both hands, you can compare them.
Let’s start with the FindWinnerStraight function.
FindWinnerStraight
FindWinnerStraight = function(hand1, hand2) {
SET workingHand1 = CardMatchUtils.SortCardsByDescendingValue(hand1);
SET hand1Info to an empty object { }
CardMatchUtils.AreCardsStraight(workingHand1, hand1Info)
SET workingHand1 = WildsAssumeValues(workingHand1, hand1Info)
SET sortedHand2 = CardMatchUtils.SortCardsByDescendingValue(hand2);
SET hand2Info to an empty object { }
CardMatchUtils.AreCardsStraight(workingHand2, hand2Info)
SET workingHand2 = WildsAssumeValues(workingHand2, hand2Info)
SET winningPlayerIndex = CardMatchUtils.CompareHands(workingHand1, workingHand2)
RETURN winningPlayerIndex
}
In the psuedocode above, you may have noticed the AreCardsStraight function from before, but it now has a new parameter that wasn’t there before: “info”.
We’ll need to make some adjustments to the AreCardsStraight, because if wilds are in the hand, we want to know what values will be replacing these wilds (using the three steps above). We can store the values in the info.cardValues array, same one we’ve used in previous hand comparing functions.
So, our new ‘AreCardsStraight’ function looks like this:
AreCardsStraight
AreCardsStraight = FUNCTION(sortedHand, info) {
SET numWilds to CardMatchUtils.CountCardsByValue(sortedHand, CardValues.wild)
SET cardValues to an empty array []
SET currentCardValue to 0
(these will be used later, but we want to set them up here)
SET highestCardValue to null
SET lowestCardValue to null
FOR EACH card in the sortedHand {
IF this card (the current loop card) is a wild card
IF (highestCardValue EQUALS null)
(this is the first card being checked)
SET highestCardValue to CardValues.ace + 1
END
EXIT FOR EACH LOOP
END
IF (this card is the first card being checked)
SET currentCardValue to the value of this card (card.value)
SET highestCardValue to currentCardValue
CONTINUE FOR LOOP again with next card (in other words, "continue" if you're familiar with for-loops)
END
SET valueDifference to currentCardValue - card.value
SET currentCardValue to card.value
IF valueDifference EQUALS 1
CONTINUE FOR LOOP again with next card (the condition for the straight is met so far)
END
IF valueDifference EQUALS 0
RETURN FALSE (this card has the same value as the previous card's stored in currentCardValue, the card from the previous loop iteration - this hand is not a straight)
END
SET lowestCardValue to currentCardValue
(check if there are enough wilds remaining to cover the difference in card values)
SET numWildsToUse to valueDifference - 1
IF numWilds GREATER THAN 0 AND numWilds IS GREATER THAN OR EQUALS numWildsToUse
(there are enough wilds, deduct that from the number of wilds available, and straight is still satisfied
SET numWilds to numWilds - numWildsToUse
(fill in the actial card values that will be replacing the wilds)
SET wildIndex to 0
WHILE wildIndex IS LESS THAN numWildsToUse
(repeat these steps as long as the WHILE condition is true)
SET substitutedCardValue to cardValue + wildIndex + 1
ADD substitutedCardValue into array cardValues
SET wildIndex to wildIndex + 1
END
ELSE
RETURN FALSE (there are not enough wilds to cover the range in value between the two cards - this hand is not a straight)
END
END
(straight is satisfied through all cards - success!)
(if there are any wilds remaining, try to assume values higher than the highest non-wild)
IF highestCardValue EQUALS null
SET highestCardValue to CardValues.ace
END
SET numWildsToUse to numWilds
WHILE (numWildsToUse IS GREATER THAN 0) {
SET cardValue to highestCardValue + (numWilds - numWildsToUse) + 1
IF (cardValue IS LESS THAN OR EQUALS CardValues.ace)
ADD cardValue into array cardValues
SET numWildsToUse to numWildsToUse - 1
ELSE
EXIT WHILE LOOP
END
END
(if there are any wilds remaining after assuming the higher values, try to assume values lower than the lowest non-wild)
IF (lowestCardValue EQUALS null
SET lowestCardValue to highestCardValue
END
SET offset to 0
WHILE offset IS LESS THAN numWildsToUse
SET cardValue to lowestCardValue - offset - 1
ADD cardValue into array cardValues
SET offset to offset + 1
END
IF info IS SPECIFIED
SET info.numWilds to numWilds
SET into.cardValues to array cardValues
END
RETURN TRUE
}
Wow! ๐ฎ This is a little more than our original AreCardsStraight function! But it now handles all three steps of replacing wilds with the correct card values. If you got nothing else from this, know that the AreCardsStraight can now return to you those cardValues. ๐
Note that this function does not replace the cards in the hand itself. We’ll be doing that next; the main function of AreCardsStraight is still to determine if a hand is straight, and you can specify an optional info only if you need to know how many wilds are in the hand, and which card values would replace them to make a wild-less hand.
Replacing The Wild Cards With Card Values
Going back to the FindWinnerStraight, you maye have noticed a new function you’ve never seen before, called WildsAssumeValues. It accepts two parameters, a hand (an array or Card objects), and an info object. What this function will do is return a new hand, with all the wilds replaced with the values specified in the info.cardValues array.
Let’s have a look.
WildsAssumeValues
WildsAssumeValues = function(hand, info) {
SET index to 0
WHILE index IS LESS THAN number of cards in the hand (for example, "hand.length")
SET card = hand[index] (get the nth card in hand)
IF the card is a wild (card.value EQUALS CardValues.wild)
SET the card value to the last value in the info.cardValues array
REMOVE the last card value from the info.cardValues array (info.cardValues.pop())
END
SET index = index + 1
END
SET sortedHand to CardMatchUtils.SortCardsByDescendingValue(hand)
RETURN sortedHand
}
All the WildsAssumeValues does is go through the hand, replacing any wilds it finds with a value from the info.cardValues array. Then, it removes that value from the array to make sure it’s not used again. Finally, it creates a new hand and sorts the cards by card value in descending order, and returns that new hand. This new hand is what we’ll use to compare straights with.
Back in the FindWinnerStraight function, at this point, you’ll now have two hands with any wilds replaced with actual card values, and you can finally compare both hands using the CardMatchUtils.CompareHands function.
Remember, CardMatchUtils.CompareHands will return 1 if the first hand wins, -1 if the second hand winds, or 0 if both hands are tied.
That’s it for comparing two straight hands! Now, if you like, you can play with creating your own hands using the controls below. Enjoy! ๐
Compare Your Own Hands
Player 1
Card 1
Card 2
Card 3
Card 4
Card 5
Result:
Player 2
Card 1
Card 2
Card 3
Card 4
Card 5
Result:
Player 3
Card 1
Card 2
Card 3
Card 4
Card 5
Result:
Who Won:
If you have any questions about anything in this article, please let me know at cartrell@gameplaycoder.com.
When you have two poker hands and both are a three of a kind, this article will show you how to compare those hands and determine which one wins.
In a previous article for poker hands, you saw how to compare a hand to determine if a hand was three of a kind. A three of a kind is a hand three of the cards are the same value, and the remaining two cards are of different, non-pair values. Here’s an example of a three of a kind:
There are three 7s, and the remaining two cards, the eight and ten, are different values from the sevens and each other, so they don’t form a pair.
When determining the winner between two hands that are both three of a kind, the process is very similar to the pair’s, except we’re dealing with a trio instead fo a pair:
Compare the values of the trios.
If those values are equal, compare the values of other two cards (the “kickers“), starting with the highest one.
Continue comparing kickers until a kicker from one hand is higher than the other’s.
If no kicker breaks the tie, and all cards have been compared, then both hands are equal.
Some examples should help with explaining the concepts.
Consider these two hands:
Hand 1
Hand 2
Note: Just like with pairs being first sorted by the pairs,, the cards are sorted first the trio, then by the kickers in descending order of value. The hands above are already sorted this way.
First, compare the value of the trios. Hand 1 has trio of 8s, and hand 2 has a trio of 9s. So hand 2 wins this contest.
Let’s try another. Let’s say the values of the trios of both hands are the same as shown here:
Hand 1
Hand 2
Both hands have the same trio value of three. So you compare the kickers.
The values of first the kicker of each hand is a seven, so we’re tied. Let’s compare the second and final kicker. You can see that 6 > 4, so the first hand has the higher three of a kind.
And we can’t forget about our crazy wild cat wild cards! ๐ผ They always seem to throw a ๐ต ๐ง into our plans. But we’re going to consider them as well.
Have a look:
Hand 1
Hand 2
In hand 1, we have a trio value of kings, and the a wild card is one of the kickers. Hand 2 also has a trio value of kings (the wild card substituting as a king). Since both hands have the same trio value (king), let’s compare the kickers.
Remember that a wild card can assume any value, and in our case, we want the wild card to assume the highest possible value (while still satisfying the hand and form the highest possible hand: see the note below). In the case of hand 1, the wild card assumes the value of a ace. If you compare that to hand 2’s first kicker, an ace beats a 10. So hand 1 is the winner here.
Note: In hand 1 above, you could’ve also formed the three of a kind by substituting the wild for a king like this:
However, if you use as many non-wild cards as possible to form your three of a kind, when using wild cards won’t increase the trio value, you can save any remaining wilds for as kickers. It will always be substituted as an ace, thus giving you the highest possible hand. When comparing hands, the code introduced in this article will help with that.
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 Threes Of Kinds
When two hands are both a pair of jacks or better, the GetWinningHand function will eventually call a function that compares two hands of said poker hand.
In this case, GetWinningHand function will eventually call FindWinnerJacksOrBetter to compare the hands. Just like FindWinnerHighCard from the last article, FindWinnerJacksOrBetter 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.
FindWinnerThreeKind
FindWinnerThreeKind = function(hand1, hand2) {
sortedHand1 = CardMatchUtils.SortCardsByDescendingValue(hand1);
SET hand1Info to an empty object { }
CardMatchUtils.DoCardsHaveSameValue(hand1, 3, hand1Info);
sortedHand2 = CardMatchUtils.SortCardsByDescendingValue(hand2);
SET hand2Info to an empty object { }
CardMatchUtils.DoCardsHaveSameValue(hand2, 3, hand2Info);
SET winningIndex = CompareTrios(hand1, hand1Info, hand2, hand2Info);
IF (winningIndex NOT EQUAL TO -1)
RETURN winningIndex (one hand's trio outranks the other hand's, and no further checking is necessary)
END
(both hands have the same ranking trio, now compare the kickers of both hands)
SET winningIndex = CompareKickers(hand1, hand1Info, hand2, hand2Info);
RETURN winningIndex;
}
Comparing the Trios
First the code above sets the hands up for comparing their trios. It then sort the cards in descending card value. Next, it uses the DoCardsHaveSameValue function to get the three cards in the hand that make the trio, as well as determine the card value of the trio.
CompareTrios
CompareTrios = function(hand1, hand1Info, hand2, hand2Info) {
SET hand1WorkingTrioValue = hand1Info.cardValues[0]
IF (CardMatchUtils.CountCardsByValue(hand1, WILD_VALUE) GREATER OR EQUALS 3)
hand1WorkingPairValue = ACE_VALUE
SET hand2WorkingTrioValue = hand2Info.cardValues[0]
IF (CardMatchUtils.CountCardsByValue(hand2, WILD_VALUE) GREATER OR EQUALS 3)
hand2WorkingTrioValue = ACE_VALUE
IF (hand1WorkingTrioValue > hand2WorkingTrioValue)
RETURN 0 (hand 1 has the higher ranking trio)
ELSE IF (hand1WorkingTrioValue < hand2WorkingTrioValue)
RETURN 1 (hand 2 has the higher ranking trio)
END
RETURN -1 (both hands' trios have the same value)
}
This function is very similar to the ComparePairs function in our recent article for comparing pairs of jacks or better, except instead of dealing with two cards, we’re dealing with three. If you’d like details on the workings of that function, please check here.
Comparing the Kickers
If the trios of both hands have the same rank, then you’ll need to compare the other two cards, the kickers.
Like you did when comparing the kickers with previous poker hands, when comparing the kickers, you first remove the trios from both hands so you’re left with the remaining kickers. You can use the CardMatchUtils.BuildHandExcludingValues function to remove the trio.
You can use this psuedocode to get the kickers in the hand:
GetKickers
GetKickers = function(hand, info) {
(get the value of the cards that form the trio)
SET trioCardValue = info.cardValues[0]
(count the number of cards in the hand that match the trio card value)
SET numTrioValueCards = CardMatchUtils.CountCardsByValue(hand, trioCardValue)
(if there are at least as many trio value cards as there are non-kicker cards, specify the trio card value to the values of cards to exclude)
SET numNonKickerCards = 3
IF numTrioValueCards >= numNonKickerCards
SET valuesToExclude = trioCardValue
ELSE {
(otherwise, if there are at least as many wild cards as there are non-kicker cards, add the wild card value to the values of cards to exclude)
SET numWildCards = CardMatchUtils.CountCardsByValue(hand, CardValues.WILD)
IF numWildCards >= numNonKickerCards
SET valuesToExclude = CardValues.WILD
ELSE
(finally, specify BOTH, the trio card value and the wild card value as the values of cards to exclude)
SET valuesToExclude = [ CardValues.WILD, trioCardValue ]
END
}
(create the temporary kickers hand by excluding the specified values and returning the rest)
SET handOfKickers = CardMatchUtils.BuildHandExcludingValues(hand, valuesToExclude, numNonKickerCards)
(finally, sort the kickers hand in descending order, with wilds as the highest value)
handOfKickers = CardMatchUtils.SortCardsByDescendingValueHighWilds(handOfKickers)
RETURN handOfKickers
}
In the GetKickers above, the info object is the same one used in FindWinnerThreeKind. It was the hand1Info or hand2Info object, depending on which hand you’re getting the kickers from.
There are three situations in GetKickers that determine which values of cards to exclude as kickers.
The first is the simplest. It’s the trio card value used to form the three of a kind; they obviously can’t be the kickers. That means they will be excluded, leaving the remaining two cards as the kickers.
The second situation is that if the hand contains at least three wilds cards. These cards can assume the highest non-wild value, which is an ace. So three wilds would form a three of a kind, using an ace as the trio card value. So the wild card value would be excluded from the hand of kickers.
Finally, the hand doesn’t have three cards with the same value, but it does contain two wild cards. Those wilds will still assume the value of the highest non-wild card, forming the three of a kind. The trio card value is whatever value those wilds card assumed. In this situation, you want to exclude both values of both, the wild card, and the trio card value.
Note: When excluding cards, you’re always excluding exactly three cards (the number of non-kicker cards).
Comparing The Kickers
I hope you are still with me at this point. If you’re reading this far, I suppose it goes without asking ๐
When comparing which three-of-a-kind hand winds, if the trio values of both hands are the same, then you need to compare one or both of the kicker cards from both hands to determine the winner.
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
}
The CardMatchUtils.CompareHands function is the same one we used here.
The CompareKickers will return 0 if hand1 has the better kickers (and thus the better three-of-a-kind-hand), 1 if hand2 has the better kickers, or -1 if both hands are the same rank.
That’s it for this article. As we write more solutions, we can often re-use code from previous ones to help simply and speed up the process.
Compare Your Own Hands
You can use the controls below to build your own hands and compare threes of kinds. Have some fun playing around with it, and if you find an issue, please let me know!
Player 1
Card 1
Card 2
Card 3
Card 4
Card 5
Result:
Player 2
Card 1
Card 2
Card 3
Card 4
Card 5
Result:
Player 3
Card 1
Card 2
Card 3
Card 4
Card 5
Result:
Who Won:
If you have any questions about the content in this article, go ahead and let me know at cartrell@gameplaycoder.com.
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:
Compare the values of each hand’s higher pair.
If those values are equal, compare the values of each hand’s lower pair.
If those are equal, compare the values of the final card (the “kickers” ) in each hand.
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:
The hand of cards, already sorted in descending order, wilds last.
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:
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:
A pair formed using a wild was possible
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
Card 1
Card 2
Card 3
Card 4
Card 5
Result:
Player 2
Card 1
Card 2
Card 3
Card 4
Card 5
Result:
Player 3
Card 1
Card 2
Card 3
Card 4
Card 5
Result:
Who Won:
If you have any questions about anything in this article, please let me know at cartrell@gameplaycoder.com.
A jacks or higher pair is a poker hand that where exactly two of its cards have the same value, which is a jack or higher.
When determining the winner between two hands that are jacks-or-better pairs, follow this process.
Compare the values of the pairs.
If those values are equal, compare the values of other three cards (the “kickers“), starting with the highest one.
Continue comparing kickers until a kicker from one hand is higher than the other’s.
If no kicker breaks the tie, and all cards have been compared, then both hands are equal.
Let’s look at some examples.
Say we have these two hands:
Hand 1
Hand 2
It’s best to sort the cards in descending value order (from highest to lowest), first by the pairs, then by the kickers. So we rearrange the cards in both hands to look like:
Hand 1
Hand 2
Note: The suits don’t matter, only the order of the card values.
You can see that hand 1 has a pair of kings, while hand 2 has a pair of jacks. Kings easily beats jacks, so hand 1 wins.
But what both hands hand pairs of the same value? Let’s try another.
Hand 1
Hand 2
After sorting, we get:
Hand 1
Hand 2
Both hands have a pair of queens, so we’ll need to look at the three kicker cards of each hand.
The first one is a 9 in both hands, so you move onto the next card. The second is a 7 in both hands, still no tie breaker. So we move on to the final card. Hand 1 has a 2, while hand 2 has a 3. So hand 2 has the higher-ranking pair and wins this battle.
Setup
Note: The first stages of the setup can be found on the introduction page to comparing poker hands, here ( https://gameplaycoder.com/how-to-code-poker-hands-comparing-hands/#setup ).
There aren’t any other specific preparations we need before we begin.
Writing The Code For Comparing Pairs of Jacks Or Better
When two hands are both a pair of jacks or better, the GetWinningHand function will eventually call a function that compares two jacks or better pairs.
In this case, GetWinningHand function will eventually call FindWinnerJacksOrBetter to compare the hands. Just like FindWinnerHighCard from the last article, FindWinnerJacksOrBetter 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 -1 (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.
FindWinnerJacksOrBetter
FindWinnerJacksOrBetter = function(hand1, hand2) {
sortedHand1 = CardMatchUtils.SortCardsByDescendingValue(hand1);
SET hand1Info to an empty object { }
CardMatchUtils.DoCardsHaveSameValue(hand1, 2, hand1Info);
sortedHand2 = CardMatchUtils.SortCardsByDescendingValue(hand2);
SET hand2Info to an empty object { }
CardMatchUtils.DoCardsHaveSameValue(hand2, 2, hand2Info);
SET winningIndex = ComparePairs(hand1, hand1Info, hand2, hand2Info);
IF (winningIndex NOT EQUAL TO -1)
RETURN winningIndex (one hand's pair outranks the other hand's, and no further checking is necessary)
END
(both hands have the same ranking pair, now compare the kickers of both hands)
SET winningIndex = CompareKickers(hand1, hand1Info, hand2, hand2Info);
RETURN winningIndex;
}
Comparing the Pairs
The first half of this function sets up the hands for comparing their pairs. It sorts the cards in descending card value. Next, it uses the DoCardsHaveSameValue function to get the two cards in the hand that make up the pair.
But there is a problem here. We’d like to compare the values of the pairs here, and you may recall that DoCardsHaveSameValue only tells us if there are a certain number of cards in the hand that have the same value (in this case 2). It doesn’t tell us what that value is.
So, you’ll need to make some adjustments to your DoCardsHaveSameValue function. We can add this data to our custom wildsInfo parameter.
Open your CardMatchUtils source file, and find the DoCardsHaveSameValue function. Inside that function, at the beginning of it, add a new variable named cardValues and assign it an empty array [].
Next, if an info object was sent as a parameter to the DoCardsHaveSameValue function, assign its cardValues property to your cardValues variable:
if ("cardValues" in info) {
cardValues = info.cardValues;
}
Next, at every point within DoCardsHaveSameValue, when the function is about to return true (this is also when it updates its info parameter if one was specified just before returning), add the following code:
Add the current base card value to your cardValues array: cardValues.push(u_baseCardValue);
Add the cardValues array as a property to your info object: info.cardValues = cardValues;
What this code does is tell us what the value of the card was that was found the requested number of times.
Let’s have a look at a quick example: say we have this hand:
If we called DoCardsHaveSameValue(hand, 2, info), the function would return true, because it found two queens. Also, the info object would have a new cardValues property that would be set to [12], because CardValues.QUEEN has a value of 12, and that was the value of the card that was found the two times we requested.
We need the value of the first element in the info.cardValues array from each hand to compare their pair values.
So, from CardMatchUtils.DoCardsHaveSameValue(hand1, 2, hand1Info) in our FindWinnerJacksOrBetter function, there will be a hand1Info.cardValues property you can now use. We’ll make use of these in the ComparePairs(hand1, hand1Info, hand2, hand2Info) function. See below:
ComparePairs
ComparePairs = function(hand1, hand1Info, hand2, hand2Info) {
SET hand1WorkingPairValue = hand1Info.cardValues[0]
IF (CardMatchUtils.CountCardsByValue(hand1, WILD_VALUE) GREATER OR EQUALS 2)
hand1WorkingPairValue = ACE_VALUE
SET hand2WorkingPairValue = hand2Info.cardValues[0]
IF (CardMatchUtils.CountCardsByValue(hand2, WILD_VALUE) GREATER OR EQUALS 2)
hand2WorkingPairValue = ACE_VALUE
IF (hand1WorkingPairValue > hand2WorkingPairValue)
RETURN 0 (hand 1 has the higher ranking pair)
ELSE IF (hand1WorkingPairValue < hand2WorkingPairValue)
RETURN 1 (hand 2 has the higher ranking pair)
END
RETURN -1 (both hands' pairs have the same rank)
}
Since we now have the values of the pairs in both hands, we could’ve just compared hand1Info.cardValues[0] to hand2Info.cardValues[0]. But instead, we performed an additional check if the hand contained at least two wild cards (see below), then assigned the working pair value to the ace value. That’s because if we did only a cardValues[0] comparison, that presents a problem when wild cards are involved.
Remember, to satisfy the requirements of CardMatchUtils.DoCardsHaveSameValue, a wild card assumes the value of the highest non-wild card. So if you had a hand like this:
The wild card would assume a value of a king, and you’d have a pair of kings.
But what if you had a hand with, not one, but TWO wilds in it!? (gasp o: )
Normally, one of the wilds would still try to assume the value of the highest non-wild card. in this case, it would be a 9, but this does not for a jacks-or-higher pair. Instead, we could simply have the two wilds themselves form the pair, and assume the highest non-wild value, which would be ace. So the pair of wilds acts like a pair of aces.
So, if the CountCardsByValue call finds two wild cards in the hand, the working pair value for that hand will be CardValues.WILD, instead of the value found in cardValues[0].
Note: You want to check if there are at least two wild cards, because, say hand 1 contained two wilds, and hand 2 contained three. The wilds in both hands would form a pair, and hand 2 would have an extra wild card left over. This third wild, however, is not involved in the pair, but would be a kicker, substituting as an ace.
Comparing the Kickers
If the pairs of both hands have the same rank, then we’ll need to compare the other three cards, the kickers, and see which hand, if either, is finally a winner.
When comparing the kickers, it would be great if we could first remove the pairs from both hands so we’re only left with the remaining three cards of each. This would also remove situations where the value of a pair might not be the highest value in the hand. The two cards that make up the pair aren’t necessarily at the beginning of the hand, (when ordered by descending card value). For example, the hand could contain a pair of queens, but the highest card is a king.
So, you can remove the cards that make up the pair (including wilds) by writing a new function to go into CardMatchUtils file. Let’s call this function BuildHandExcludingValues. This function will create a copy of a hand, with specific cards excluded from the copy. It takes three parameters:
cards – The hand (an array of Card objects)
valuesToExclude – An array of card values that are to be excluded from the new copy, if they are found in cards
maxCountToExclude – The maximum count of cards that can be excluded. This is useful to prevent the function from excluding too many cards. For example, a hand may have three queens in it; we only want to remove two, and the third one is a kicker.
Without further ado, tis BuildHandExcludingValues function:
BuildHandExcludingValues
BuildHandExcludingValues = function(cards, valuesToExclude, maxCountToExclude) {
SET copyHand = [] (this is our new hand; set it up as an empty array)
SET currentCountExcluded = 0 (keep track of the number of cards excluded)
FOR EACH card IN cards
IF (card.value does not match any of the values in valuesToExclude)
add the card to the copyHand array
ELSE
IF currentCountExcluded LESS THAN maxCountToExclude
increment currentCountExcluded by 1 (this card is effectively "excluded" from the copy)
ELSE
add the card to the copyHand array (the max number of excluded cards has been reach; include card in the copy, even if it's supposed to be excluded)
END
END
END
RETURN copyHand
}
Let’s have a look at two quick examples.
Say you have this hand:
Your pair would be the king and the wild (acting as the other king). Your kickers are the three remaining cards.
If you called BuildHandExcludingValues with valuesToExclude set to [ CardValues.KING, CardValues.WILD ], and maxCountToExclude set to 2, the copy returned would look like:
These are the three kickers.
Now, consider this hand:
After calling BuildHandExcludingValues with valuesToExclude set to [ CardValues.QUEEN ], and maxCountToExclude set to 2, the copy returned would look like:
In this case, the queens form a pair without using a wild, so the wild becomes a kicker that assumes the highest value (ace).
Before you compare the kickers of both hands, you’ll need to sort them in descending order, but this time, wilds will be placed first (as the highest value) instead of last like usual. You’ll use the new function CardMatchUtils.SortCardsByDescendingValueHighWilds that you wrote in the last article.
The comparison of the kickers can be made with another new function that you can place in CardMatchUtils: CardMatchUtils.CompareHands. You’ll see how this function works below.
CompareKickers
CompareKickers = function(hand1, hand1Info, hand2, hand2Info) {
(build a temporary hand that contains only the kickers from hand 1)
SET valuesToExclude = [ CardValues.WILD ]
IF (CardMatchUtils.CountCardsByValue(hand1, WILD_VALUE) NOT EQUAL 2)
add hand1Info.cardValues[0] to the valuesToExclude array
SET hand1Kickers = CardMatchUtils.BuildHandExcludingValues(hand1, valuesToExclude, 2)
hand1Kickers = CardMatchUtils.SortCardsByDescendingValueHighWilds(hand1Kickers)
(build a temporary hand that contains only the kickers from hand 2)
SET valuesToExclude = [ CardValues.WILD ]
IF (CardMatchUtils.CountCardsByValue(hand1, WILD_VALUE) NOT EQUAL 2)
add hand2Info.cardValues[0] to the valuesToExclude array
SET hand2Kickers = CardMatchUtils.BuildHandExcludingValues(hand2, valuesToExclude, 2)
hand2Kickers = CardMatchUtils.SortCardsByDescendingValueHighWilds(hand2Kickers);
(compare the two temporary hands)
SET winningPlayerIndex = CardMatchUtils.CompareHands(hand1Kickers, hand2Kickers)
RETURN winningPlayerIndex
}
CompareHands
CardMatchUtils.CompareHands = function(hand1, hand2) {
(both hand1 and hand2 should contain the same number of cards in them, but if they don't, use the hand with fewer cards as the number of cards to
compare)
SET numberOfCardsToCompare = MIN(hand1.length, hand2.length)
FOR cardIndex = 0 TO numberOfCardsToCompare
(get the nth card from each hand)
SET card1 = hand1[cardIndex]
SET card2 = hand2[cardIndex]
(get the card value of both cards to compare; treat wilds as aces)
SET card1Value = MIN(card1.value, CardValues.ACE)
SET card2Value = MIN(card1.value, CardValues.ACE)
IF (card1Value GREATER THAN card2Value)
RETURN 0 (hand 1 has a higher ranking hand)
ELSE IF (card1Value LESS THAN card2Value)
RETURN 1 (hand 2 has a higher ranking hand)
END IF
END
(all cards in both hands are equal)
RETURN -1
}
The CardMatchUtils.CompareHands function accepts two parameters: both players’ hands. The hands are the temporary ones that include only the kickers, and should already be sorted in descending order with wilds at the beginning of the order. The function compares cards in both hands, starting with each hand’s first card, then second if necessary, and so on. It returns 0 if hand1 has a higher hand, 1 if hand2 has a higher hand, or -1 if both hands are equal. The value returned gets passed back up to the function that called it, CompareKickers, which passes the returned value back up to the original calling function, FindWinnerJacksOrBetter.
That pretty much wraps it up for this article! When you have a physical deck of cards, and you compare two poker hands, it’s easy to determine which one wins. But when you have to write out the process for doing so, step by step, it’s a bit more challenging that you might realize. ๐
Compare Your Own Hands
You can use the controls below to build your own hands and compare pairs of jacks or better. Now that you have two poker hands, high card and jacks or better pairs, you can also compare those two ranks, and you’ll see that the pair will always beat the high card. Have some fun playing around with it, and if you find an issue, please let me know!
Player 1
Card 1
Card 2
Card 3
Card 4
Card 5
Result:
Player 2
Card 1
Card 2
Card 3
Card 4
Card 5
Result:
Player 3
Card 1
Card 2
Card 3
Card 4
Card 5
Result:
Who Won:
If you have any questions about recognizing a royal flush, or the above interaction, please let me know at cartrell@gameplaycoder.com.
Thanks, and stay tuned, because we have more poker hands to cover in this series!