0

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

jerdiggity
  • 3,655
  • 1
  • 29
  • 41

4 Answers4

1

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
Michel
  • 4,076
  • 4
  • 34
  • 52
0

have a look on max function of php.

http://php.net/manual/en/function.max.php

jagad89
  • 2,603
  • 1
  • 24
  • 30
0

What about this? Not sure I understood the questions and I didn't test it but maybe it will help.

$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) {
      if($increment_value[$player_id] == 1) {
          $top_card_key = $player_cards[$player_id][key]
          $top_card[$top_card_key] = 1;
      }
      $increment_value[$player_id]++;
      if(isset($top_card[$top_card_key])) {
          $top_card[$top_card_key]++;
      }
    }
    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]);

      // Foreach on top_card, check which one == 5  and display it 
      // return the top_card;
    }
0

here is your answer, I commented it as best i could. Notice there is a part in there not needed for flush, which is true, but I took the liberty to group the cards as well. You will see this in the output. The keys of the top array are the card values, and the array count of that item is the number of multiple cards, and I think you can figure out what to do with those.

    foreach( $hands as $cards ){
        rsort($cards);
        //holding array for sequential cards
        $seq = array();
        $_cards = array();
        foreach( $cards as $key => $card){
            $c_value = $card['value_num'];
            // < start --- not needed for flush  - need these without the nested array 
            if( !isset( $_cards[$c_value] ) ){
                $_cards[$c_value] = array($c_value);
            }else{
                $_cards[$c_value][] = $c_value;
            }
            //end --- not needed for flush >
            //expect last item from seq - 1 ( initially -1 )
            $expected = end($seq) - 1;
            if(count($seq) < 5 && !in_array( $c_value, $seq )){
                if( $c_value ==  $expected){
                    //match add to sequence
                    $seq[] = $c_value;
                }else{
                    //fail, reset sequence to start at this card
                    $seq = array($c_value);
                }
            }
        }
        print_r( $seq );
        echo '<br>';
        print_r( max($seq));
        echo '<br>';
        print_r($_cards);
        echo '<br>------------<br>';
    }

outputs

Array
(
    [0] => 10
    [1] => 9
    [2] => 8
    [3] => 7
    [4] => 6
)

10
Array
(
    [14] => Array
        (
            [0] => 14
        )

    [10] => Array
        (
            [0] => 10
        )

    [9] => Array
        (
            [0] => 9
        )

    [8] => Array
        (
            [0] => 8
            [1] => 8
        )

    [7] => Array
        (
            [0] => 7
        )

    [6] => Array
        (
            [0] => 6
        )

)

------------
Array
(
    [0] => 10
    [1] => 9
    [2] => 8
    [3] => 7
    [4] => 6
)

10
Array
(
    [14] => Array
        (
            [0] => 14
        )

    [13] => Array
        (
            [0] => 13
        )

    [10] => Array
        (
            [0] => 10
        )

    [9] => Array
        (
            [0] => 9
        )

    [8] => Array
        (
            [0] => 8
        )

    [7] => Array
        (
            [0] => 7
        )

    [6] => Array
        (
            [0] => 6
        )

)

------------
Array
(
    [0] => 9
    [1] => 8
    [2] => 7
    [3] => 6
    [4] => 5
)

9
Array
(
    [14] => Array
        (
            [0] => 14
        )

    [12] => Array
        (
            [0] => 12
        )

    [9] => Array
        (
            [0] => 9
        )

    [8] => Array
        (
            [0] => 8
        )

    [7] => Array
        (
            [0] => 7
        )

    [6] => Array
        (
            [0] => 6
        )

    [5] => Array
        (
            [0] => 5
        )

)

------------
Array
(
    [0] => 9
    [1] => 8
    [2] => 7
    [3] => 6
    [4] => 5
)

9
Array
(
    [14] => Array
        (
            [0] => 14
        )

    [13] => Array
        (
            [0] => 13
        )

    [9] => Array
        (
            [0] => 9
        )

    [8] => Array
        (
            [0] => 8
        )

    [7] => Array
        (
            [0] => 7
        )

    [6] => Array
        (
            [0] => 6
        )

    [5] => Array
        (
            [0] => 5
        )

)

as a side note comparing the card count before and after this can predict if you need to check for pairs ect.., as no pairs no items removed.

$cards = array_unique( $cards );
ArtisticPhoenix
  • 21,464
  • 2
  • 24
  • 38