Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a simpler way than this to calculate a straight in poker?

I have an algorithm for calculating whether a player's hand holds a straight in Texas Hold'em. It works fine, but I wonder if there is a simpler way to do it that does not involve array/string conversions, etc.

Here's a simplified version of what I have. Say the player is dealt a hand that is a 52-element array of card values:

var rawHand = [1,0,0,0,0,0,0,0,0,0,0,0,0, //clubs
               0,0,0,0,0,0,0,0,0,0,0,0,0, //diamonds
               0,1,1,0,1,0,0,0,0,0,0,0,0, //hearts
               0,0,0,1,0,0,0,0,1,0,0,0,0];//spades

A 1 represents a card in that value slot. The above hand has a 2-clubs, no diamonds, a 3-hearts, 4-hearts, and 6-hearts, a 5-spades and a 10-spades. Now I look at it to find a straight.

var suits = []; //array to hold representations of each suit

for (var i=0; i<4; i++) {
    var index = i*13;
    // commenting this line as I removed the rest of its use to simplifyy example
    //var hasAce = (rawHand[i+13]);

    //get a "suited" slice of the rawHand, convert it to a string representation
    //of a binary number, then parse the result as an integer and assign it to
    //an element of the "suits" array
    suits[i] = parseInt(rawHand.slice(index,index+13).join(""),2);
}

// OR the suits    
var result = suits[0] | suits[1] | suits[2] | suits[3];

// Store the result in a string for later iteration to determine
// whether straight exists and return the top value of that straight
// if it exists; we will need to determine if there is an ace in the hand
// for purposes of reporting a "low ace" straight (i.e., a "wheel"),
// but that is left out in this example
var resultString = result.toString(2);

//Show the result for the purposes of this example
alert("Result: " + resultString);

The trick here is to OR the various suits so there is just one 2-to-Ace representation. Am I wrong in thinking there must be a simpler way to do this?

like image 344
Robusto Avatar asked Oct 23 '10 16:10

Robusto


3 Answers

Almost all of the work your code does is type conversion. If you just had the hand stored in bit format to begin with(needs > 32 bit type), you could do something like:

var mask = 2^13 - 1; // this will zero out all but the low 13 bits
var suits = (rawHand | rawHand>>13 | rawHand>>26 | rawHand>>39) & mask;

The equivalent using a one line loop would be:

var suits = [];
for(var i=0; i < 13; i++) {
   suits[i] = rawHand[i] || rawHand[i+13] || rawHand[i+26] || rawHand[i+39];
}

This is much shorter and easier to understand.

Converting to and from a bit-wise representation takes more code and CPU time than you save by using the bit-wise OR operator.

like image 138
Mike Edwards Avatar answered Oct 02 '22 20:10

Mike Edwards


Well, a straight must include a 5 or a 10, so you can start by throwing out the hand if it doesn't have one or other:

if (rawHand[3] || rawHand[16] || rawHand[29] || rawHand[42] ||
    rawHand[8] || rawHand[21] || rawHand[34] || rawHand[47]) {
  // do some more checks
} else {
  // not a straight
}
like image 44
Tim Avatar answered Oct 02 '22 20:10

Tim


You can use an integer value as a bitfield for the card values, ace gets two spots low and high. Then you compare with bitwise end against the ten possible straights.

Or use a for-loop and check for five consecutive numbers - effectively it's all the same.

like image 38
Eiko Avatar answered Oct 02 '22 19:10

Eiko