module pixelperfectengine.system.rng;

/** 
 * Implements a pseudo-random number generator using a 64 bit Fibonacci LFSR.
 *
 * Example uses:
 * * `rng.seed() % maxAmount`
 * * `(rng.seed() % 100) < probabilityOfEvent`
 */
public struct RandomNumberGenerator {
	protected ulong     reg;
	/** 
	 * Creates the LFSR, and initializes it by calling its seed function 64 times.
	 */
	public this (ulong reg) @nogc @safe pure nothrow {
		this.reg = reg;
		for (int i ; i < 64 ; i++)
			seed();
	}
	/** 
	 * Shuffles the register's content, then returns it.
	 */
	public ulong seed() @nogc @safe pure nothrow {
		const ulong bit = 
				~(reg ^ (reg >> 51) ^ (reg >> 53) ^ (reg >> 54) ^ (reg >> 55) ^ (reg >> 59) ^ (reg >> 62) ^ (reg >> 63));
		reg = (reg>>1) | (bit<<63);
		return reg;
	}
	/** 
	 * Calls seed, then returns the remainder of the seed divided by s.
	 * Intended to simplify the use of `rng.seed() % s` style of use of this 
	 */
	public ulong dice(const uint s) @nogc @safe pure nothrow {
		return seed % s;
	}
	public ulong opCall() @nogc @safe pure nothrow {
		return seed();
	}
}