Add classes for random number generation (RNG)
Created by: lmbarros
This is perhaps more a request for comments than a real pull request. I still have some doubts about how to do things the Godot way (see my questions below), but overall this is the design I'd personally like to see in the engine.
It is used like this:
var rng = RandPCG32.new() # Or another RNG class, like Xoroshiro128Plus
rng.seed(1234) # rng.randomize() also exists
n = rng.uniform_float(-1.0, 2.0) # uniform in interval [-1.0, 2.0]
n = rng.uniform_int(1, 6) # six-sided die
n = rng.boolean(0.1) # 10% of chance of being true
n = rng.normal(-3.0, 2.0) # Gaussian, mean = -3, std. deviation = 2.0
n = rng.exponential(2.0) # from exponential distribution with mean = 2.0
I believe the current random number generation facilities in Godot are good for simple use cases (and I'd say that they should remain available), but more "interesting" RNG usage needs something new. I had three main goals in mind:
-
Add a few more useful distributions beyond uniform.
-
Let the user create separate instances of the RNG algorithm, in order to generate different independent sequences (pretty useful for procedural generation of content).
-
Allow users to be sure that they can create reproducible pseudorandom sequences even between Godot releases.
The biggest open points and questions I still have are:
- Do you consider this design in general good for Godot?
- One sub-question here: What about providing multiple RNG algorithms as I did? I think that choosing a RNG is a trade-off, so I like the idea of providing the alternatives and letting the user chose one. Providing one single
Rand
class would be simpler (which is good), but if we ever decide to replace the one algorithm with something else, my point 3 above is not achieved. And I like RNG algorithms, so my opinion is biassed :-)
- One sub-question here: What about providing multiple RNG algorithms as I did? I think that choosing a RNG is a trade-off, so I like the idea of providing the alternatives and letting the user chose one. Providing one single
- How to add tests for this? I am currently using a Godot project (https://github.com/lmbarros/GodotRandTest/ -- it is currently quite ugly, BTW) that calls my methods from GDScript and checks if the results are OK. However, in order to be able to make these tests, I was required to expose
Rand::random()
to GDScript, which otherwise I wouldn't. - Sometimes it is useful to save the RNG state with a saved game (to avoid the save-reload-and-try-again "cheat"). I am a Godot beginner, so I don't know if there is any support or standard way for doing serialization or save games.
- The newer versions of the C++ standard have implementations of various RNG algorithms and random distributions. For some reason that beyond my own understanding I haven't used them here. Is the usage of these newer parts of the C++ standard library allowed or encouraged in Godot?
- I implemented this on Linux and didn't test anywhere else. There is nothing platform-specific here, but we may need to tweak the implementation a bit to make it compile everywhere.
Six RNG algorithms are provided: PCG32, Xoroshiro128+, two variations of Mersenne Twister (MT19937 and MT19937-64), SplitMix64 and a simple LCG. Different random distributions are provided: uniform (for integers and floats), normal (Gaussian), exponential and Bernoulli (for generating Booleans).
All algorithms and distributions are usable from GDScript.
The base Rand
class contains the interface that must be implemented by
all RNG algorithms and the implementation of the different
distributions. Subclasses that implement each of the actual RNG
algorithms inherit the distributions. This way, new algorithms and new
distributions can be easily added, and every algorithm can be used with
every distribution.