using System; namespace RobotAndDonkey.Game.Utils; /// /// Implements a XorShift* PRNG, with 64 bits of internal state. /// See http://en.wikipedia.org/wiki/Xorshift /// public struct SRandom { public SRandom(ulong seed) { if (seed == 0) throw new InvalidOperationException("Seed needs to be bigger than zero."); Seed = seed; } public void Shuffle(Span span) { var n = span.Length; for (var i = 0; i < n; i++) { var r = i + Next(n - i); (span[r], span[i]) = (span[i], span[r]); } } public ulong Next() { Seed ^= Seed >> 12; Seed ^= Seed << 25; Seed ^= Seed >> 27; return Seed * 2685821657736338717UL; // multiplier taken from wikipedia article on XorShift PRNGs } public ulong Next(ulong upperLimit) { if (upperLimit == 0) return 0; return Next() % upperLimit; } public uint Next(uint upperLimit) { if (upperLimit == 0) return 0; return (uint)(Next() % upperLimit); } public uint Next(uint lowerLimit, uint upperLimit) { if (upperLimit == 0) return 0; if (lowerLimit == upperLimit) return lowerLimit; return lowerLimit + (uint)(Next() % (upperLimit - lowerLimit)); } public int Next(int upperLimit) { if (upperLimit == 0) return 0; return (int)(Next() % (uint)(upperLimit & 0x7fffffff)); } public int Next(int lowerLimit, int upperLimit) { if (upperLimit == 0) return 0; if (lowerLimit == upperLimit) return lowerLimit; return lowerLimit + (int)(Next() % (uint)((upperLimit - lowerLimit) & 0x7fffffff)); } public double NextDouble() { return Next(int.MaxValue) * (1.0 / int.MaxValue); } public float NextSingle() { return (float)NextDouble(); } public readonly override string ToString() { return $"0x{Seed:X}"; } public ulong Seed { get; internal set; } }