0

I have a program which gives out 10 random cards from a normal deck (and doesn't put them back in).
Sometimes when I run the script in the shell I recieve the following error message:

PHP Notice: Undefined offset: ..... on line 15

My code looks as follows:

<?php
  $deck = array(
      array('A', 2, 3, 4, 5, 6, 7, 8, 9, 10, 'J', 'Q', 'K'), //club
      array('A', 2, 3, 4, 5, 6, 7, 8, 9, 10, 'J', 'Q', 'K'), //spade
      array('A', 2, 3, 4, 5, 6, 7, 8, 9, 10, 'J', 'Q', 'K'), //heart
      array('A', 2, 3, 4, 5, 6, 7, 8, 9, 10, 'J', 'Q', 'K')  //diamond
  );

  $i = 0;
  for ($i = 1; $i <= 10; $i++) {
      $a = rand(0, 3);        //card's suit
      $nr = count($deck[$a]); //how many cards of the suit are available?
      $b = rand(0, $nr--);    //pick a random number out of the available ones
      $card = $deck[$a][$b];  //pick a card [---LINE 15---]

      switch ($a) {
          case 0:
              $c = "club";
              break;
          case 1:
              $c = "spade";
              break;
          case 2:
              $c = "heart";
              break;
          case 3:
              $c = "diamond";
              break;
      }

      echo $c . " " . $card . "\n" . "remaining: " . $nr . "\n";

      unset($deck[$a][$b]);    //remove the card you drew
      array_values($deck[$a]); //rearrange the index of the suit you drew the card from
  }
?>

Could someone help a newbie out?

Nisse Engström
  • 4,738
  • 23
  • 27
  • 42
  • 1
    why dont you print $a and $b to check what it is returning?? and then try to find if the deck has that index or not – Exprator Aug 04 '17 at 10:09
  • Because you are `unset()`-ing cards. They no longer exists in array. Your script probably tries to give duplicate card. – BlitZ Aug 04 '17 at 10:09
  • 2
    `$nr--` only decrements after the rand function is called, you have to use `--$nr` or just `$nr - 1` – xander Aug 04 '17 at 10:10

4 Answers4

2

you have to replace $b = rand(0, $nr--); with $b = rand(0, --$nr);

This is because $foo -- is a post decrementation : the value is decremented after the var is used.

Also on the last line, you don't use the result of array_value() you should do this : $deck[$a] = array_values($deck[$a]);

Pre/post increment and decrement

More info on pre/post incrementation and decrementation here : http://php.net/manual/en/language.operators.increment.php

ᴄʀᴏᴢᴇᴛ
  • 2,939
  • 26
  • 44
0

If you unset a $deck position array, and in some other iteration of the for you try to access that same position, it gives you an undefined offset error because that offset no longer exists.

  • That is what I use array_values($deck[$a]); for – user3187119 Aug 04 '17 at 10:19
  • That's why the function `array_values()` is called at the end of the loop : it produces an array containing the same values then the one passed as a parameter but with successive numeric indexes whatever their keys were. It's great for cleaning arrays in which you unset stuff. – Sarkouille Aug 04 '17 at 10:20
0

First, thanks for providing the error with the line and hinting what that line is in the code you proviced, really appreciated.

count($deck[$a]) returns how many entries are currently in that array. As an example, at the begining of your for, it will return 13. Since the first index of an array is 0, the king's index will be 12.

That means that each time your code tries to pick a card, there is one chance out of $nr that the offset it will use will not exist.

$nr = count($deck[$a]) - 1; By removing 1 from the array's count from the start, $nr has the correct value right when it's setted. Assigning its value that way should correct your problem, and also remove the need of decrementing it in the next line :

$nr = count($deck[$a]) - 1;
$b = rand(0, $nr); 
Sarkouille
  • 1,275
  • 9
  • 16
0

This will eliminate your error:

Code: (Demo)

$ranks=['A',2,3,4,5,6,7,8,9,10,'J','Q','K'];
$suits=['club','spade','heart','diamond'];  // store suit names, avoid switch-case
foreach($suits as $suit){
    shuffle($ranks);  // shuffle once, avoid future rand() on subarray
    $deck[]=$ranks;   // store shuffled suit cards
}
for($x=0; $x<10; ++$x){
    $i=rand(0,3);  // pick random suit / subarray key
    echo $suits[$i],' ',array_pop($deck[$i]),' remaining ',sizeof($deck[$i]),"\n";
}

This not only gets your job done, it cuts down on extra function calls.

p.s. I like cards.

mickmackusa
  • 43,625
  • 12
  • 83
  • 136