1

I'm trying to simulate a Wild Pokemon encounter. As stated in the formula:

The rate of Pokémon encounter is determined from a simple mathematical formula:
1 in (187.5 / ( x )) per step.

Let x equal the a value which determines how rare the Pokémon is. The higher the encounter rate, 
the more common the Pokémon is.

Encounter-rate Table
Encounter type Encounter rate
Very common     10
Common          8.5
Semi-rare       6.75
Rare            3.33
Very rare       1.25

I want to run this probability after every press of a button. How do I simulate this with rand()?

Dale Julian
  • 1,560
  • 18
  • 35
  • 1
    Can I talk you into using [`std::discrete_distribution`](https://en.cppreference.com/w/cpp/numeric/random/discrete_distribution) instead of `rand`? [`rand` kinda sucks.](https://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful) – user4581301 Mar 27 '19 at 01:43
  • @user4581301 sure! – Dale Julian Mar 27 '19 at 01:52
  • Sadly on re-read, `std::discrete_distribution` isn't quite the right tool for the job. It's perfect for weighting encounters, but that's not quite what you are doing here. If it was, the code would look something like: https://ideone.com/Vud9UC – user4581301 Mar 27 '19 at 02:34

2 Answers2

1

I would do it this way

Mapping rand()

rand() / (float)RAND_MAX

Rand() returns a value from 0 to RAND_MAX so this formula maps 0 -> RAND_MAX to 0 -> 1

(float) is used to make RAND_MAX a float because the value returned by rand() is an int and int / int in c++ returns an int

(rand() / (float)RAND_MAX) * 10 

If you multiply the result by 10 it will map rand() from 0 -> 10

(rand() / (float)RAND_MAX) * 187.5

This will map rand() from 0 -> 187.5

1 in 187.5

We mapped the value of rand() from 0 -> 187.5

Now everytime we call rand() it will return a random number from 0->187.5

To simplify let's say we map rand() from 0 -> 200

There will be a 1/2 chance that rand() will return a number lower then 100 because every number between 0 -> 200 has an equal chance of being returned (for example rand() can return 25.67 or 100.9 or 140.6)

( (rand() / (float)RAND_MAX) * 187.5 ) < 1

By the same principle there is a 1 in 187.5 chance that the number returned is smaller then 1

Final solution

We are still missing the 1 in 187.5 / X

To implement the encounter rate you just need to change the mapping from 0 -> 187.5 To

0 -> 187.5 / X

We can see that if X is big it means that there is a high encounter rate and 187.5 gets smaller and the number returned has a higher chance of being smaller then 1 but if the encounter rate is low X becomes small and 187.5 gets bigger (lower chance of being smaller then 1)

Final code

srand (time(NULL)); // Init rand() with a seed
bool encountered = ( (rand() /  (float)RAND_MAX) * (187.5 / x) ) < 1

Optimisation

A user pointed out that with the last code you need to compute 5 rand()'s for each event but if we tweak the formula a little bit you can compute only 1 rand()

By using simple math you know that an event that occurs once (1) in 10 / 2 steps is an event that occurs twice in (2) in 10 steps

So an event that occurs once (1) in 187.5 / X steps occurs (1 * X) in 187.5 steps

If we map rand() from 0 -> 187.5 Then for each pokemon we can calculate a unique value for it using only one rand()

float randomNumber      = (rand() / (float)RAND_MAX) * 187.5
bool encountedPokemon1  = randomNumber < 1 * encounter_rate_first_pokemon
bool encountedPokemon2  = randomNumber < 1 * encounter_rate_second_pokemon
  • Good discussion and works as well as anything does with `rand` if there is only one event. There are 5 possible events. So either you are generating five numbers and give five tries at getting an encounter every step or you have to do something else. – user4581301 Mar 27 '19 at 15:28
  • I didn't want to add this because the user seems to be new to c++ but i will do it now that you pointed that out – mohamed azaiez Mar 27 '19 at 18:17
0

use the modulo operator. rand() will return a number between 0 and the highest value an integer can hold. so rand()%10 will return a number between 0 and 9.

(rand()%1875) <= 10 should be true 1 out of 187.5 times (or 10 out of 1875)

In case you don't already know, % will give you the remainder. So x%10 can never be greater than 9.

Here is a reference