I'm trying to calculate whether or not a user has a straight in a poker hand using values from an associative array.
Each player's hand is inside the same array, the structure of which being similar to this:
<?php
// Note: the first 5 values of each player's hand are identical because those are
// the dealer's cards (the cards on the "board" that everyone can see).
// The last two values represent the player's "hole cards" that only they can see.
// Also note: 11 = Jack, 12 = Queen, 13 = King, 14 = Ace.
$hands = array(
// Player 0
0 => array(
0 => array("value_num" => 6),
1 => array("value_num" => 7),
2 => array("value_num" => 8),
3 => array("value_num" => 9),
4 => array("value_num" => 14),
5 => array("value_num" => 10),
6 => array("value_num" => 8),
),
// Player 1
1 => array(
0 => array("value_num" => 6),
1 => array("value_num" => 7),
2 => array("value_num" => 8),
3 => array("value_num" => 9),
4 => array("value_num" => 14),
5 => array("value_num" => 10),
6 => array("value_num" => 13),
),
// Player 2
2 => array(
0 => array("value_num" => 6),
1 => array("value_num" => 7),
2 => array("value_num" => 8),
3 => array("value_num" => 9),
4 => array("value_num" => 14),
5 => array("value_num" => 5),
6 => array("value_num" => 12),
),
// Player 3
3 => array(
0 => array("value_num" => 6),
1 => array("value_num" => 7),
2 => array("value_num" => 8),
3 => array("value_num" => 9),
4 => array("value_num" => 14),
5 => array("value_num" => 5),
6 => array("value_num" => 13),
),
);
The function I've written to determine if the player has a straight looks like this:
<?php
/**
* @return
* The highest card value of the player's straight, if they have a straight.
* Otherwise, 0.
*/
function has_straight($cards, $player_id, $required_consecutive_cards = 5) {
// Extract the "value_num" values to calculate the straight.
for ($i = 0; $i < count($cards[$player_id]); $i++) {
$values[$player_id][$i] = $cards[$player_id][$i]['value_num'];
}
// Check to see if the player has an Ace within their hand.
$has_ace[$player_id] = array_search(14, $values[$player_id]);
// If the player has an Ace, push a 1 into their $value array in case they also
// have 2, 3, 4, and 5 in their hand.
if ($has_ace[$player_id] !== FALSE) {
array_push($values[$player_id], 1);
}
// Only check the player's unique values. Right now we're not concerned with
// pairs or anything else.
$player_cards[$player_id] = array_unique($values[$player_id]);
// Reverse sort the player's unique values to make counting sequences easier.
rsort($player_cards[$player_id]);
// Set a number to increment if one card is sequential to the other.
$increment_value[$player_id] = 1;
foreach ($player_cards[$player_id] as $key => $value) {
$next_key = $key + 1;
$next_value = $value - 1;
if (!array_key_exists($next_key, $player_cards[$player_id])) {
return 0;
}
if ($player_cards[$player_id][$next_key] == $next_value) {
$increment_value[$player_id]++;
}
else {
$increment_value[$player_id] = 1;
unset($player_cards[$player_id][$key]);
}
if ($increment_value[$player_id] == $required_consecutive_cards) {
// Reverse sort what's left of the values so that the first one can be
// the value returned.
rsort($player_cards[$player_id]);
return $player_cards[$player_id][0];
}
}
return 0;
}
So, to determine if player 0 has a straight, you could run this:
<?php
$player_to_check = 0;
print has_straight($hands, $player_to_check);
... which should result in 10
as the output (10
being the highest value within player 0's straight -- 6
, 7
, 8
, 9
, 10
).
The problem I'm having is when, for example, you check player 1's straight -- which should be identical to player 0's straight -- the output will be 14
instead of 10
.
The reason this is happening is because player 1 also has a 13
in his hand, and since 13
is sequential with 14
, 14
is returned instead of 10
(even though 14
is not within player 1's straight).
The same problem can be seen when you compare players 3 and 4.
What do I need to do inside the function to make it so the highest value within the set of 5 sequential numbers is returned (as opposed to the highest value of the first set of sequential numbers found)?
A straight has 5 consecutive cards, with a sum always obeying this rule: (n*5)+10. Where n is the starting card. The higher the sum, the higher the starting card. So this could be a solutiuon:
foreach($player_id as $id){
//GET THE CARD VALUES FROM THIS PLAYER
$cards=array();
foreach($player_cards[$id] as $tmp){
$cards[] = $tmp['value_num'];
}
//ONLY THE UNIQUE CARDS
$cards=array_unique($cards);
//SORT THEM LOW TO HIGH
sort($cards);
//Get the maximum amount of possabilities for a straight from
//the maximum 7 cards in a hand
$max=count($cards)-4;
//IF TOO LITTLE CARDS, CONTINUE WITH NEXT PLAYER
if($max<=0)continue;
//SET SUM and HIGHEST SUM
$sum=0;
$hsum=0;
//LOOP THE POSSIBLE STRAIGHTS
for($i=1;$i<$max+1;++$i){
//GET 5 CONSECUTIVE CARDS
$straight=array_slice($cards,$i-1,5);
$sum_should_be=($straight[0]*5)+10;
$sum = array_sum($straight);
//IF SUM NOT CORRECT, CONTINUE WITH NEXT POSSIBLE STRAIGHT
if($sum!=$sum_should_be)continue;
//GET THE HIGHEST STRAIT FOR USER
if($sum>$hsum)$hsum=$sum;
//ADD STRAIGHT SCORE TO ARRAY FOR COMPARISON
$straight_score[$id]=$straight[4];
}
}
It will give you:
Player 0. Straight score: 10
Player 1. Straight score: 10
Player 2. Straight score: 9
Player 3. Straight score: 9