Mystic
Mystic

Reputation: 157

PHP Split int into random values

I have a int called v_cnt which im using a maximum value for a voting system, them im using mt_rand to generate a random number of 'votes' (used for gaming purposes not a rigged system)

// vote 1
$vote_limit = $v_cnt;
$vote_1 = mt_rand(0, $vote_limit); 
// vote 2
$vote_limit = $v_cnt - $vote_1; if($vote_limit < 0){ $vote_limit = 0;}
$vote_2 = mt_rand(0, $vote_limit);
// vote 3
$vote_limit = $v_cnt - ($vote_1 + $vote_2); if($vote_limit < 0){ $vote_limit = 0;}
$vote_3 = mt_rand(0, $vote_limit);

This gives me vote_1, vote_2 and vote_3 which is ideal. But, since mt_rand is a random value up to the limit, im not getting quite the result i need as i need it to calculate like this;

(vote_1 + vote_2 + vote_3) = $v_cnt

So essentially i need to split an int into 3 random values which must add up to equal the starting number. I hope this makes sense.

Thank you.

Upvotes: 0

Views: 81

Answers (2)

Andreas
Andreas

Reputation: 23958

You can't have all three random. It's impossible.
The first two, sure. But the last one can only be one number and that is what is remaining.

// vote 1
$vote_limit = $v_cnt;
$vote_1 = mt_rand(0, $vote_limit); 
// vote 2
$vote_limit = $v_cnt - $vote_1; 
$vote_2 = mt_rand(0, $vote_limit);
// vote 3
$vote_3 = $v_cnt - ($vote_1 + $vote_2); 

https://3v4l.org/2C2bu

Also I'm not sure what you expect this line to do: if($vote_limit < 0){ $vote_limit = 0;}.
$vote_limit can't be negative since you have a limit of the random number.


I see that you have added a request to have unique numbers.
I created a new code that outputs $n_votes votes that is all unique and none is negative and all in between 0 and $v_cnt.

$v_cnt = 100;
$n_votes = 3;

$numbers = range(0,$v_cnt); // create array of 0->100
shuffle($numbers); // shuffle the array
$votes = array_fill(0, $n_votes-1, 1); // create an array that will NOT exit loop below.
// Array_fill returns [1,1,1] which does not match the requirements so the loop starts

//Loop until all values in votes are unique and none is negative
while(count(array_unique($votes)) != $n_votes || $votes[$n_votes-1]<1){
    // Take two consecutive numbers of random place in the array
    $votes = array_slice($numbers, mt_rand(0, $v_cnt-$n_votes+1),$n_votes-1);
    // Count what the last item should be
    $votes[] = $v_cnt - array_sum($votes);
}
echo array_sum($votes) . "\n";
Var_dump($votes);

https://3v4l.org/2h7DB

Just as a fun thing to look at, if I include a $i in the code we can see how many tries in the loop was needed to create the unique array. https://3v4l.org/mPae5
Keep in mind this code is very sensitive to max limit opposed to number of votes.
If you have a relatively low $v_cnt and a high $n_votes it may never find the numbers needed.
Just try and set $n_votes to 5 in the latest link and you can see that $i number can be 100+ (meaning more than 100 loops was needed to get a correct set of numbers).

Upvotes: 1

Simon K
Simon K

Reputation: 1523

here is how I would handle this...

$vote_limit = $v_cnt;
$numbers_required = 3;

for($i=1;$i<=$numbers_required;$i++)
{

    if($i != $numbers_required)
    {

        $votes[$i] = mt_rand(0, $vote_limit);
        $vote_limit -= $votes[$i];

    } else {

        $votes[$numbers_required] = $v_cnt - array_sum($votes);

    }

}

echo $votes[1]; // First
echo $votes[2]; // Second
echo $votes[3]; // Third

Upvotes: 0

Related Questions