using System; using System.Runtime.CompilerServices; namespace MoonTools.ECS { // WELLRNG512 // https://stackoverflow.com/a/1227137 public class Random { public const int STATE_BYTE_COUNT = 68; // 16 state ints + 1 index int uint[] State = new uint[16]; uint Index = 0; uint Seed; public Random() { Init((uint) Environment.TickCount); } public void Init(uint seed) { Seed = seed; uint s = seed; for (int i = 0; i < 16; i++) { s = (((s * 214013 + 2531011) >> 16) & 0x7fffffff) | 0; State[i] = ~ ~s; //i ; } Index = 0; } public uint GetSeed() { return Seed; } public string PrintState() { var s = ""; for (var i = 0; i < 16; i += 1) { s += State[i]; } s += Index; return s; } // expects a span of STATE_BYTE_COUNT bytes public unsafe void SaveState(Span bytes) { #if DEBUG if (bytes.Length < STATE_BYTE_COUNT) { throw new ArgumentException("Byte span too short!"); } #endif fixed (byte* ptr = bytes) { var offset = 0; for (var i = 0; i < 16; i += 1) { Unsafe.Write(ptr + offset, State[i]); offset += 4; } Unsafe.Write(ptr + offset, Index); } } // expects a span of STATE_BYTE_COUNT bytes public unsafe void LoadState(Span bytes) { #if DEBUG if (bytes.Length < STATE_BYTE_COUNT) { throw new ArgumentException("Byte span too short!"); } #endif fixed (byte* ptr = bytes) { var offset = 0; for (var i = 0; i < 16; i += 1) { State[i] = Unsafe.Read(ptr + offset); offset += 4; } Index = Unsafe.Read(ptr + offset); } } private uint NextInternal() { uint a, b, c, d; a = State[Index]; c = State[(Index+13)&15]; b = a^c^(a<<16)^(c<<15); c = State[(Index+9)&15]; c ^= (c>>11); a = State[Index] = b^c; d = (uint) (a ^((a<<5)&0xDA442D24UL)); Index = (Index + 15)&15; a = State[Index]; State[Index] = a^b^d^(a<<2)^(b<<18)^(c<<28); return State[Index]; } // .NET Random API always returns a non-negative signed int. Fun! public int Next() { return (int) (NextInternal() >>> 1); // unsigned bitshift right to get rid of signed bit } public int Next(int n) { return (int) (((double) Next()) * n / int.MaxValue); } public int Next(int min, int max) { var diff = max - min; var next = Next(diff); return min + next; } public long NextInt64() { long next = NextInternal(); next <<= 32; next |= NextInternal(); next >>>= 1; return next; } public long NextInt64(long n) { var next = NextInt64(); return (long) (((double) next) * n / long.MaxValue); } public long NextInt64(long min, long max) { var diff = max - min; var next = NextInt64(diff); return min + next; } public float NextFloat() { var n = NextInternal(); return ((float) n) / uint.MaxValue; } public double NextDouble() { var n = NextInternal(); return ((double) n) / uint.MaxValue; } } }