Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create RNG module #96

Open
JohnathonNow opened this issue Oct 11, 2019 · 6 comments
Open

Create RNG module #96

JohnathonNow opened this issue Oct 11, 2019 · 6 comments
Labels
enhancement New feature or request Hacktoberfest help wanted Extra attention is needed

Comments

@JohnathonNow
Copy link
Collaborator

Right now many of the elements of RNG are hardcoded. I suggest a new RNG module, perhaps
rng.c and rng.h.

There should be the following functions, at least:

int rng_rand(int max); //returns a random number in the range [0, max]
int rng_roll(int droprate); //returns 1 with probability 1/droprate, else 0

rng_rand should be sure to account for the limitations of rand in C. Namely, if the argument to rng_rand is greater than RAND_MAX but less than INT_MAX, it should piece together the result from multiple rand calls.

Further, rng_rand and rng_roll should both use rejection sampling to ensure that the randomness is uniform across their respective ranges. That is, rng_rand(max) should return every number in [0, max] with equal probability, and rng_roll(droprate) should always yield 1 with probability 1/droprate in the long run.

Finally, rng.h should define the constants for various probabilities.

@JohnathonNow JohnathonNow added enhancement New feature or request Hacktoberfest help wanted Extra attention is needed labels Oct 11, 2019
@Apoorv-Gaurav-Agarwal
Copy link
Contributor

I would like to help with this

@Apoorv-Gaurav-Agarwal
Copy link
Contributor

Apoorv-Gaurav-Agarwal commented Oct 14, 2019

What will be the constants for the probabilities. Can you provide example?

@Apoorv-Gaurav-Agarwal
Copy link
Contributor

Also, random number generated should be both 0 and max inclusive?

@JohnathonNow
Copy link
Collaborator Author

Yes, it should return in the range [0, max].

@Pacheco95
Copy link

Can you better explain the last two paragraphs?

@JohnathonNow
Copy link
Collaborator Author

JohnathonNow commented Oct 17, 2019

rng_rand should be sure to account for the limitations of rand in C. Namely, if the argument to rng_rand is greater than RAND_MAX but less than INT_MAX, it should piece together the result from multiple rand calls.

Say RAND_MAX is 32767, which is the lowest number it is allowed to be. Now say we want something to happen 1 in 50000 times. If we do rand() % 50000 and check if the result is 0, it will be 1 in 32767 times instead, as rand() will not return anything greater than RAND_MAX. This is sad, because wanting something that rare is perfectly reasonable, and 50000 is nowhere near the maximum size 4 bytes can get you. A common solution is to then piece together the results of rand() by using bit shifting to create a wider range of return values. This is not currently done, but is low priority, as almost everybody will be compiling with GCC, where RAND_MAX == INT_MAX.

Further, rng_rand and rng_roll should both use rejection sampling to ensure that the randomness is uniform across their respective ranges. That is, rng_rand(max) should return every number in [0, max] with equal probability, and rng_roll(droprate) should always yield 1 with probability 1/droprate in the long run.

rand() can return any value in [0, RAND_MAX] This is problematic if we wanted, say, a uniformly random number in [0, 5] (that is, one of 0, 1, 2, 3, 4, 5, or what you'd expect from a fair die roll where the die was painted by a programmer) and RAND_MAX % 6 != 5 . To see why, consider if RAND_MAX was something small, like 9 (it can't be that low, but this is just an example).

In that case, rand() could return 0, 1, 2, 3, 4, 5, 6, 7, 8, 9. If we do the usual thing of rand() % 6 to get our number, then this is our distribution of rolls:

Roll Value Probability rand() return values
0 2 / 10 0 or 6
1 2 / 10 1 or 7
2 2 / 10 2 or 8
3 2 / 10 3 or 9
4 1 / 10 4
5 1 / 10 5

As you can see, in this case, simply moding the result of rand() by the number of elements in the range we want would lead to a biased distribution. One solution is to re-call rand if it returns something that is in that last "incomplete" section of return values, which in our case is anything above 5. Doing that, we would re-roll anytime we saw a 6 or greater, and every side of the die would have a 1/6 chance of being returned. This is what we want.

This was addressed in #110, so no need to worry about it anymore.

Finally, rng.h should define the constants for various probabilities.

There should be a header file for various constants used for things that happen with a chance.
For example, item.c scales the maximum power of a weapon by 10*(floor_number + 1) - this
10 here could be a constant in rng.h such as RNG_WEAPON_POWER_SCALE.
Or how main.c checks luck against rand() % 20000 for a crit chance. That 20000 should be a constant with a name like RNG_CRIT_THRESHOLD.
This is not done, and is of a sensible priority level.

Repository owner deleted a comment from peteroupc Jul 13, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request Hacktoberfest help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

3 participants