tags:

views:

91

answers:

7
<?php
        if (isset($_POST['Roll!'])) {
                    $sides = $_POST['sides'];
                    $rolled = rand(1,$sides);

                    echo "$rolled was rolled by the dice, it is now out!";
        }
?>

This is the code I currently have. After rolling that number, however, I want it to roll again, but without the previously rolled number, until it has rolled all number except one, which would be the winning number. I have no idea how to go about doing that. Any ideas?

EDIT: I'm sorry, I should have been more clear, thank you all for the help so far, but I also need to echo each number rolled, such as

echo "$rolledArray[0] was rolled, it lost.\n";
echo "$rolledArray[1] was rolled, it lost.\n";
echo "$rolledArray[2] was rolled, it lost.\n";
echo "$rolledArray[3] was rolled, it lost.\n";
echo "$rolledArray[x] was rolled, it lost.\n";
echo "$rolledArray[x] was rolled, it lost.\n";
echo "$rolledArray[50?] was rolled, it lost.";

EDIT AGAIN: Also I only want them to have to click Roll! once, not multiple times until they've rolled all the numbers, meaning no need for session, I think, though I could be wrong, most of you are clearly more experienced than me.

Sorry, I should have mentioned that before as well.

+2  A: 

I think you need to have array $thrownNumbers, which holds every number previously thrown. And every new throw (OMG... the word), you check if it's in array. If yes, throw again. Simplest possible solution.

Edit: As for keeping the array during moving to another page, you can use:

  • $_SESSION
  • cookies (hm)
  • have serialized array as hidden value in form

There.

Adam Kiss
That doesn't seem to be possible with this (or not as straightforward), because it's responding to a form submission. Each page load gets a new instance of the interpreter and therefore the array would not be available on the next page load... you need some sort of way to save the state, i.e. persistence.
Alex JL
There is my reply :)
Adam Kiss
+1  A: 

You can throw it in the $_SESSION to keep track of it between posts/request or append it to the URL and pass it yourself each time as a URI param.

Mr-sk
Session is a good idea. I wouldn't use the URL as it would be open to tampering (of course, I don't know the asker's mission here or whether that matters).
Alex JL
Agreed - URL is bad, but its not like this is tampering a SQL query, where if someone tampers this, its not a sploit - but still yeah I agree with you. +1
Mr-sk
+1  A: 
<?php
if(!isset($_SESSION['numbers']){
 $_SESSION['numbers'] = range(1,6); //same as array(1,2,3,4,5,6)
}
$numbers = $_SESSION['numbers'];

if(count($numbers)>1){ //is more than one number left
 $rand_index = array_rand($numbers); //choose a number from an array, returns the index
 print('you rolled '.$numbers[$rand_index].' loser'); // tell them they lost
 unset($numbers[$rand_index]); //remove that element from the array
 $_SESSION['numbers'] = $numbers; //set new array back to session
}else{
 print(array_pop($numbers).' is the winner!'); //pop the remaining number out of the array and print it with winner notification
}
?>

edit: updated to session usage

Mike Sherov
...or the other way around :) ...
Adam Kiss
I think this now deals with the desired answer most effectively.
Mike Sherov
+1  A: 

just create an array (or other type of list) of all possible numbers and randomly order it. Then, instead of picking a new number each time just advance through the array until you get to the last but one.
alternatively, you could just go straight to the last number in the list and that's th winner.

Matt Lacey
+5  A: 

To answer your direct question: You can put all of the possible numbers into an array, and get a random index for that array. Once you have an index, remove the item from the array and redo the random over the smaller array:

$possible = range(1, $_POST['sides']);     // build the possible values
$rolledIndex = rand (0, count($possible)); // get a random index
$rolled = $possible[$rolledIndex];         // get the rolled number

unset($possible[$rolledIndex]);            // and remove the rolled nuber

// now you can simply redo the random:
$rolledIndex = rand (0, count($possible)); // get a random index on the smaller array
$rolled = $possible[$rolledIndex];         // get the 2nd rolled number

However, If you want to have a random order on the dice throws, simply use this:

// generate an array with all values from 1 to the posted value (e.g. 1,2,3,4,5,6)
$possible = range(1, $_POST['sides']);  

// this reorders the array by random (e.g. 4,3,1,5,2,6)
$throwOrder = $possible;
shuffle($throwOrder); 
print_r($throwOrder);

Now you can simply iterate over the $throwOrder array and have a random order of dice throws:

Array (
    0 => 4,
    1 => 3,
    2 => 1,
    3 => 5,
    4 => 2,
    5 => 6
)

Edit To get the desired output from the second method, simply do this:

// get the last index of the array of thrown dices
$lastIndex = count($throwOrder)-1;
// iterate through the array, printing the results
foreach ($throwOrder as $key => $rolled) {
    // check if the current key matches the last key in the array
    if ($key != $lastIndex) {
        // if not, the number has lost
        echo $rolled, " was rolled, it lost.\n";
    } else {
        // we have reached the last element of the array
        echo $rolled, " was the last, it won.\n";
    }
}
Cassy
I'd prefer this method, however I would not use "unset" and "rand(0,count)" but instead just "array_shuffle" followed by "array_shift" to pull a random yet never repeating value until the array is empty.
hurikhan77
Thanks for the help, but I was wondering if you could also explain all of it, maybe in comments or something. I'd like to understand what all of it does instead of just having someone else code it for me. Thanks
Rob
Hi Rob. Good approach :-) I added comments to the code (although most of the comments are just a natural way of telling what the code does, please don't copy this commenting style!)
Cassy
Ah thanks. Now how would I put this all together
Rob
Simply put the second and the fourth code block from above in one php script and call it via a post form. The rest should be straight away
Cassy
Fatal error: Call to undefined function array_shuffle()
Rob
Ooops, my bad. The correct function is `shuffle`. Sorry. I corrected it
Cassy
Warning: Invalid argument supplied for foreach()
Rob
Check the second box again, I had to change a line there... (`$throwOrder = array_shuffle($possible);` became `$throwOrder = $possible; shuffle($throwOrder);`
Cassy
Ah you're right. My mistake. Thanks a lot (: You've been much help and it's working the way I wanted it to now.
Rob
A: 

Depends on the situation but creating an array with all the posible numbers for all the visitors in your web can be a very bad idea, sessions files can grow unnecesary. if they are like numbers from 1 to 10 i think it would be ok, but if they are numbers from 1 to 1million creating arrays with those ranges saved in session its pretty much a bad idea. i think its better to save the rolled results and generate a new one until it doesnt exist in the array.

useless
so what if you have a million numbers and 998,999 were picked already. Are you going to keep generating random numbers until it randomly picks the 1/500,000 chance of finding a number it hasn't already picked? That's insane.
Mike Sherov
+1  A: 

not a bad idea add to url if you use properly. The good side is that you dont store data in session, the bad side is that the request are biggers each time. To avoid tamperinc you can use:

$url = 'numbers.php?throwed='.implode(',',$throwed).'&sign='.sha1(serialize($throwed).'mysecretpassword');

and use this to get check:

$throwed = explode(',',$_GET['throwed']);
$not_tampered = sha1(serialize($throwed).'mysecretpassword') == $_GET['sign'];
useless
+1 for the tampering! But this approach wouldn't work for a million throws, simply because a url string is limited in length. Having all numbers from 1 to 999,999 in your get string would be a length of about 7.5 million characters ...
Cassy
you can still use a post aproach, adding a hidden field on a form and keeping the same logic.
useless
@user267351: When changing to $_POST, I agree. But I think transferring gigabytes worth of data through the net just to get distinct random numbers is worse than using $_SESSION. When you come to this amount of data, i guess a bitmask with a million bits would be more feasable (125.000 bytes)
Cassy
sure, my post method isnt good enough but no one say nothing about the cookies, cookies does the same, send the results back and foward each time a request its made, and not even to one script but every script. So i guess you can say use cookies its not a good solution but really depends on how much numbers the program genetares, and if they are very little amount its better to add it to the request instead to have gygabites of session files.
useless