diff --git a/PKHeX.Core/Legality/RNG/Algorithms/XorShift128.cs b/PKHeX.Core/Legality/RNG/Algorithms/XorShift128.cs index c9091e3c6..6bb0d96b3 100644 --- a/PKHeX.Core/Legality/RNG/Algorithms/XorShift128.cs +++ b/PKHeX.Core/Legality/RNG/Algorithms/XorShift128.cs @@ -63,6 +63,26 @@ public uint Next() return w = w ^ (w >> 19) ^ t ^ (t >> 8); } + /// + /// Gets the previous random . + /// + public uint Prev() + { + var t = w ^ z ^ (z >> 19); + t ^= t >> 8; + t ^= t >> 16; + + w = z; + z = y; + y = x; + + t ^= t << 11; + t ^= t << 22; + + x = t; + return w; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public uint NextUInt() => (uint)NextInt(); diff --git a/Tests/PKHeX.Core.Tests/General/XorShiftTests.cs b/Tests/PKHeX.Core.Tests/General/XorShiftTests.cs new file mode 100644 index 000000000..272e05ce1 --- /dev/null +++ b/Tests/PKHeX.Core.Tests/General/XorShiftTests.cs @@ -0,0 +1,48 @@ +using FluentAssertions; +using PKHeX.Core; +using Xunit; + +namespace PKHeX.Tests; + +public static class XorShiftTests +{ + [Theory] + [InlineData(0x7F996375F5A791FC, 0xF3A995138EC18148, 0x50188547081C7BEC, 0x0DA245AA536BEF36, 99, 1000)] + public static void Forward(ulong s0, ulong s1, ulong n0, ulong n1, int frames, int loop) + { + var adv = GetFramesForward(s0, s1, n0, n1, loop); + adv.Should().Be(frames); + } + + [Theory] + [InlineData(0x7F996375F5A791FC, 0xF3A995138EC18148, 0x50188547081C7BEC, 0x0DA245AA536BEF36, 99, 1000)] + public static void Reverse(ulong s0, ulong s1, ulong n0, ulong n1, int frames, int loop) + { + var adv = GetFramesReverse(s0, s1, n0, n1, loop); + adv.Should().Be(frames); + } + + private static int GetFramesReverse(ulong s0, ulong s1, ulong n0, ulong n1, int loop) + { + var rand = new XorShift128(n0, n1); + for (int i = 0; i < loop; i++) + { + _ = rand.Prev(); + if (rand.GetState64() == (s0, s1)) + return i; + } + return -1; + } + + private static int GetFramesForward(ulong s0, ulong s1, ulong n0, ulong n1, int loop) + { + var rand = new XorShift128(s0, s1); + for (int i = 0; i < loop; i++) + { + _ = rand.Next(); + if (rand.GetState64() == (n0, n1)) + return i; + } + return -1; + } +}