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.

Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Dec 10, 2013 at 21:08
\$\endgroup\$
9
  • 2
    \$\begingroup\$ Ugh. You have no idea how much I wish it were that simple. \$\endgroup\$ Commented Dec 10, 2013 at 21:13
  • \$\begingroup\$ Are the cards guaranteed to be maintained as sorted? \$\endgroup\$ Commented Dec 10, 2013 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\$ Commented Dec 10, 2013 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\$ Commented Dec 10, 2013 at 21:26
  • 1
    \$\begingroup\$ Wait a minute, a straight is 5 cards, even if your hand has 7 cards ? \$\endgroup\$ Commented Dec 10, 2013 at 21:27

1 Answer 1

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.

answered Dec 10, 2013 at 21:53
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.