How to Code Poker Hands – Comparing Hands For A Straight

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:

  1. 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.
  2. 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.
  3. 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

Result:

Player 2

Result:

Player 3

Result:

Who Won:

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

Thanks, take care, and until next time,

– C. out.

How to Code Poker Hands – Straight

Continuing the series of writing code that recognizing poker hands, you’ll learn how to code a solution for determining if a hand is a straight.

A straight is a hand where all five cards are in order of sequential rank, meaning each card is the next highest (or lowest) than the one before it.

If you’d like to see poker hands that have already been covered, please check the links below.

Setup

The setup is the same as in the previous articles of this mini-series. A quick rundown of the setup is below, but if you’d like to skip ahead, click here. If you’d like to see the full details of the setup, check out this link.

Card values
CardValues = {
  two: 2,
  three: 3,
  four: 4,
  five: 5,
  six: 6,
  seven: 7,
  eight: 8,
  nine: 9,
  ten: 10,
  jack: 11,
  queen: 12,
  king: 13,
  ace: 14,
  wild: 100
};
Card suits
CardSuits = {
  hearts: 1,
  diamonds: 2
  clubs: 3,
  spades: 4
};
Card
Card = function(value, suit) {
  this.value = value;
  this.suit = suit;
};
Hand

A hand is an array of Card objects:

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

As stated earlier, a straight is a hand where each card is one value (rank) above the next card, or below the next card. An easy way to accomplish this is to first sort the cards by descending value, then check that each card is one less than the one before it.

However, the deck being used includes a “wild card”, which can assume any value. So, this makes the challenge a bit more interesting. 😏

Also, in anticipation of recognizing another poker hand that also uses a straight (the straight flush), you can place the function that you’ll be writing (called CardMatchUtils.AreCardsStraight) in the in the “utilities” file, CardMatchUtils.js. This is a file that we’ve been using to assist with matching poker hands in past articles. It contains common functions that can be used across several poker hands, so we don’t have to keep rewriting them for every poker hand.

There are two functions that CardMatchUtils will use:

  1. CardMatchUtils.SortCardsByDescendingValue – This function sorts the cards in the hand by descending value. This orders the cards from highest value to lowest.
  2. CardMatchUtils.AreCardsStraight – This function has not yet been written (but that’s what you’ll write in this article!) This function will be used in recognizing both, the straight, and the straight flush hands.

Let’s start with the pseudo code for the straight. It looks like this:

Straight = FUNCTION(hand) {
  SORT the hand by descending card value and store in a variable called sortedHand

  IF AreCardsStraight(sortedHand)
    //we have a straight!
    RETURN TRUE 

  //this hand is not a straight
  RETURN FALSE
}

It’s short and fairly straightforward. However, the AreCardsStraight function mentioned above is where all the action is. It will determine if the cards are straight, and return TRUE if they are. It takes one parameter, which is a hand (array) of cards, already sorted in descending order, by their values. The pseudo code for the AreCardsStraight function looks like:

AreCardsStraight
AreCardsStraight = FUNCTION(sortedHand) {
  count the number of wild cards in the hand and store in a variable called numWilds (to do this, you can use the `CardMatchUtils.CountCardsByValue` function that was introduced here ( https://gameplaycoder.com/how-to-code-poker-hands-pair-of-jacks-or-higher/#countCardsByValue ) )
  set a variable called currentCardValue to 0

  FOR EACH card in the sortedHand {
    IF this card (the current loop card) is the first card being checked {
      set currentCardValue to the value of this card
      re-start FOR loop again with next card (in other words, "continue" if you're familiar with for-loops)
    }

    subtract the value of currentCardValue from the value of this card and store in a variable called valueDifference
    set currentCardValue to the value of this card

    IF valueDifference EQUALS 1 {
      re-start FOR loop again with next card (the condition for the straight is met so far)
    }

    IF the card is a wild card {
      EXIT FOR LOOP (a wild card can assume any card value, including the next value to satisfy a straight, since)
    }

    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)
    }

    (check if there are enough wilds remaining to cover the difference in card values)
    IF numWilds GREATER THAN 0 AND numWilds GREAT THAN OR EQUALS valueDifference - 1 {
      (there are enough wilds, deduct that from the number of wilds available, and straight is still satisfied
      numWilds = numWilds - (valueDifference - 1)
    } ELSE {
      RETURN FALSE (there are not enough wilds to cover the range in value between the two cards - this hand is not a straight)
    }
  }

  (straight is satisfied through all cards - success!)
  RETURN TRUE
}

What the AreCardsStraight function does is take the value of the first card, and compare it to the next card’s value. If the value of the next card is one less, then the straight so far is OK, it continues checking cards. The first two card comparisons look like:

If the next card is a wild card it instead of a card whose value is one less, then the wild card will assume the value of the card with the lesser value, and it continues checking cards. Let’s say your hand is a different one, like this:

After sorting the above hand in descending value order, you’d have:

Remember in the sorting algorithm, wild cards are always placed at the end.

Once we arrive at the wild card, we can exit the loop. There is no point in further checking cards, because they will all be wild cards, assuming the next value lowest value. And AreCardsStraight returns TRUE if the end of the loop is reached. This means the hand is identified as a straight, because each card is one less value than the one preceding it.

Once the loop reaches this first wild, we are done, and can conclude that this hand is a straight.

Ok, let’s try another example.

Say you had a hand, and after sorting, looked like this:

Once we get to the queen, the next card is a 10, which is more than one value less than the queen (the jack was expected). Since you have one wild card, you can “use” it as the jack, and the straight would still be satisfied.

But wait…

What if THIS was your hand?

To cover the gap in between the 8 and 6, you’d use the wild as a 7. However, there is another gap in between the 6 and 4. Since you used the wild already – and this hand only has one wild – you can no longer substitute another wild for a 3. So hmm, I’ma ‘fraid this hand would not be a straight. 🤔

Have a look at this hand:

This hand would be a straight, because it contains two wilds to cover both gaps, between the 9 and 7, and another one between the 7 and 5. Yes!

The gaps we’ve looked at only cover a value range of one. Let’s say you had this hand (after sorting):

There are two gaps between the 7 and 4 (6 and 5), we’d need at least two wilds to cover them both. Since this hand only has one, it’s not a straight.

One more:

This hand would be a straight because it has enough wilds (at least three) to cover for the 9, 8, and 7. I know I’m getting pretty wild with wilds here, but it illustrates the point of using wild cards to support any hand to find a straight.

Build your own Hand

Like in the last article, you can use the controls below to create your own hand to see if it is a straight or not. It will also recognize previous hands we’ve covered up to this point, which are pairs (jacks or higher), two pair, and three of a kind.


Result:

If you have any questions about recognizing a straight hand, or the above interaction, please let me know at cartrell@gameplaycoder.com.

Finally, if you’d like to hire me to program an actual card game for you, please e-mail me, or you may use the contact form here.

That’s it for now. Thanks, and stay tuned as we add more poker hands. The next one will be the flush!

– C. out.