10
\$\begingroup\$

The context is Weekend Challenge #2 (Poker hand evaluation).

Hand.prototype.isStraight = function()
{
  for( var i = 1 ; i < this.cards.length ; i++ )
    if( this.cards[i].value + 1 != this.cards[i-1].value )
      return false;
  return true;
}

cards is an array with card objects { suit : "x" , value : "0->12" }. The cards are sorted during the creation of the hand.

My approach to detect straightness seems like the hard way. Can anyone suggest something else?

Okay, Poker is tough. I will revise this question once I have my new isStraight.

\$\endgroup\$
  • 2
    \$\begingroup\$ Ugh. You have no idea how much I wish it were that simple. \$\endgroup\$ – Mathieu Guindon Dec 10 '13 at 21:13
  • \$\begingroup\$ Are the cards guaranteed to be maintained as sorted? \$\endgroup\$ – Corbin Dec 10 '13 at 21:15
  • 1
    \$\begingroup\$ Indeed the straight seems to be one of the hardest things about this week's challenge. I like your approach but remember that Ace can be used as both 1 and 14 in a straight (Ace - 5 and 10 - Ace). Also, why are you starting the loop at i = 1 when arrays indexes tends to be 0-based? \$\endgroup\$ – Simon Forsberg Dec 10 '13 at 21:17
  • 1
    \$\begingroup\$ Although I have to add: If you don't want to handle both the low & high ace case, that's OK for now. \$\endgroup\$ – Simon Forsberg Dec 10 '13 at 21:26
  • 1
    \$\begingroup\$ Wait a minute, a straight is 5 cards, even if your hand has 7 cards ? \$\endgroup\$ – konijn Dec 10 '13 at 21:27
8
\$\begingroup\$

It's not that hard.

Instead of sorting the cards, looping over them and skipping double results, let's convert them to a more useful format:

var bitmap = 0;

for(var i = 0; i < cards.length; i++)
{
    var value = cards[i].value;

    // set i+1 bit in the bitmap
    bitmap |= 1 << (value + 1);

    // if it's an ace, also set the low bit
    if(value === 12)
        bitmap |= 1;
}

Now, if there's a card of value i in your hand, the i+1 bit will be set in the bitmap. An Ace is treated as two cards with values 13 and 0. Next, we scan the bitmap for 5 consecutive bits set, which is equivalent to 31 (1 | 2 | 4 | 8 | 16). We start with the highest straight, which is 9. The lowest straight is 0, if there is no straight i is -1.

for(var i = 10; i--; )
{
    if((bitmap & 31 << i) === (31 << i))
    {
        break;
    }
}

The method works for games with more than 5 cards. Note that in any variant of Poker, 5 cards make a hand, so even in Omaha with 9 cards, 5 cards give you a straight.

Note: The method is roughly equivalent to creating a set (and checking for 5 consecutive elements). As you can see, with bit-wise operators it is much simpler to check for 5 consecutive cards.

Another note: There's a harder-to-understand but slightly faster method for testing a straight given the bitmap. I might add it later, but for now I think this method hard enough to understand for beginners.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.