Skip to content

Probability Based on Increasing Distance in PHP

An answer to this question on Stack Overflow.

Question

I'm trying to get a random selection from a data set based on probability which would be determined by the amount of distance between to map points in PHP for a game. In addition, the potential records included in the dataset are determined also by the distance.

I have a table of Monsters with levels from 1 to 20. I want to be able to select a monster first based on whether or not the user has travelled enough distance.

Example 1:

  • If the distance is between 1 - 100, then only Monsters level 1,2,3 can be included
  • And the closer the distance is to 100, the more likely they will get a higher level monster (e.g. if you were at distance 100, you would be most likely to get a level 3 monster, a little less likely to get a level 2 and even more less likely to get a level 1; if you were distance 50 then most likely to get a level 2 and equally likely to get a 1 or 3.

Example 2:

  • If the distance is between 1 - 200, then the potential Monsters are level 1,2,3,4,5,6
  • Same probability methodology as Example 1, but the distribution is across more monster levels and more potential distances.

I found two articles that got me thinking in the right directions:

https://stackoverflow.com/questions/10914678/get-result-based-on-probability-distribution

https://stackoverflow.com/questions/8806006/php-percentage-chance


I'm easily able to determine the monster groupings based on distances. And I can see from the function in article 1 for example that if I knew all the possible distances within a monster group, I could assign weights to them like this:

function weighted_random($values, $weights){ 
$count = count($values); 
$i = 0; 
$n = 0; 
$num = mt_rand(0, array_sum($weights)); 
while($i < $count){
    $n += $weights[$i]; 
    if($n >= $num){
        break; 
    }
    $i++; 
} 
return $values[$i]; 
}
$values = array('A','B','C','D','E'); // Potential monster levels
$weights = array(1,20,50,75,100); // Possible distance ranges
$weighted_value = weighted_random($values, $weights);

The issue is, I only know the actual distance within the max potential distance for that group. In other words, for Monster Group 1 (A,B,C,D,E) I know the player must travel between 1 and 100 miles and I know specifically what distance they travelled (i.e 85 miles). So I can't create weightings (or don't know how) for the other Monster levels.

Note that if this question isn't specific enough please let me know and I'll work thought the solution further and post/update. I'm hoping that someone can at least give me some best practice thoughts on approach, from there I can probably figure out how to write some code to accomplish.

Answer

One way would be to use the weighted_random function you've discovered, but in a different way.

Build arrays corresponding to the probability of finding a monster class at varying distances:

$a=array(1,2,3,4,5,6,7,8,9,10);
$b=array(0,0,0,0,1,2,3,4,5, 6);
$c=array(0,0,0,0,0,0,0,1,2, 3);

This says that at distance 0 the probability of monster class A is 100%. Meanwhile, at distance 9, the probability of monster class A is 10/19, B is 6/19, and C is 3/19. Of course, you could change the numbers in the array to build whatever probability distribution you like.

To use these arrays in our program, we convert them into a 2D array:

$probtable=array();
for($i=0;$i<count($a);$i++){
   $probtable[$i]=array($a[$i],$b[$i],$c[$i]);

Now, if the distance traveled is $d then the appropriate monster weights are given by $probtable[$d] and the category is retrieved with:

weighted_random($values, $probtable[$d])

Adjust the initial arrays as needed to get the probability distribution right.