Search code examples
phparraysrandom

Get a random number from a broken range of numbers


I would like to draw a random number from the interval 1,49 but I would like to add a number as an exception ( let's say 44 ) , I cannot use round(rand(1,49)) .So I decided to make an array of 49 numbers (1-49), unset($aray[44]) and apply array_rand().

Now I want to draw a number from the interval [$left,49], how can I do that using the same array that I used before? The array now misses value 44.


Solution

  • The function pick takes an array as an argument with all the numbers you have already picked. It will then pick a number between the start and the end that IS NOT in that array. It will add this number into that array and return the number.

    function pick(&$picked, $start, $end) {
    
        sort($picked);
    
        if($start > $end - count($picked)) {
            return false;
        }
    
        $pick = rand($start, $end - count($picked));
        foreach($picked as $p) {
            if($pick >= $p) {
                $pick += 1;
            } else {
                break;
            }
        }
    
        $picked[] = $pick;
    
        return $pick;
    }
    

    This function will efficiently get a random number that is not in the array AND WILL NEVER INFINITELY RECURSE!

    To use this like you want:

    $array = array(44); // you have picked 44 for example
    $num = pick($array, 1, 49); // get a random number between 1 and 49 that is not in $array  
    
    // $num will be a number between 1 and 49 that is not in $arrays
    

    How the function works


    Say you are getting a number between 1 and 10. And you have picked two numbers (e.g. 2 and 6). This will pick a number between 1 and (10 minus 2) using rand: rand(1, 8).

    It will then go through each number that has been picked and check if the number is bigger.

    For Example:

    If rand(1, 8) returns 2. 
      It looks at 2 (it is >= then 2 so it increments and becomes 3)
      It looks at 6 (it is not >= then 6 so it exits the loop)
      The result is: 3
    
    If rand(1, 8) returns 3
      It looks at 2 (it is >= then 2 so it increments and becomes 4)
      It looks at 6 (it is not >= then 6 so it exits the loop)
      The result is 4
    
    If rand(1, 8) returns 6
      It looks at 2 (it is >= then 2 so it increments and becomes 7)
      It looks at 6 (it is >= then 6 so it increments and becomes 8)
      The result is: 8
    
    If rand(1, 8) returns 8
      It looks at 2 (it is >= then 2 so it increments and becomes 9)
      It looks at 6 (it is >= then 6 so it increments and becomes 10)
      The result is: 10
    

    Therefore a random number between 1 and 10 is returned and it will not be 2 or 6.

    I implemented this a long time ago to randomly place mines in a 2-dimensional array (because I wanted random mines, but I wanted to guarantee the number of mines on the field to be a certain number)