public static UInt[] PySeedGetStateFor(string program)
        {
            if (program.Length * 2 > MersenneTwister.N)
            {
                throw new ArgumentException($"Length of {nameof(program)} must be less than or equal to {MersenneTwister.N / 2}", nameof(program));
            }

            Dictionary <char, double> neededRngs = new Dictionary <char, double>();
            const double chancePerChar           = 1 / 96D;
            const double correction = chancePerChar / 10D;

            // Calculate required RNG output for each character
            for (char c = (char)0; c < 96; c++)
            {
                neededRngs[c == 95 ? '\n' : (char)(c + 32)] = chancePerChar * c + correction;
            }

            UInt[] state = new UInt[MersenneTwister.N];
            int    i     = 0;

            foreach (char c in program)
            {
                if (!neededRngs.TryGetValue(c, out double rng))
                {
                    continue;
                }

                (UInt a, UInt b)states = MersenneTwister.PyGetPossibleOutputs(rng);
                state[i++]             = MersenneTwister.GetState(states.a);
                state[i++]             = MersenneTwister.GetState(states.b);
            }

            return(state);
        }
 public static uint GetState(UInt n)
 {
     n = MersenneTwister.UntemperR(n, MersenneTwister.L);
     n = MersenneTwister.UntemperL(n, MersenneTwister.T, MersenneTwister.C);
     n = MersenneTwister.UntemperL(n, MersenneTwister.S, MersenneTwister.B);
     n = MersenneTwister.UntemperR(n, MersenneTwister.U, MersenneTwister.D);
     return(n);
 }
        public static UInt UntemperR(UInt n, int shift, UInt mask)
        {
            UInt cur = n;

            for (int accuracy = shift; accuracy < UInt.WIDTH; accuracy += shift)
            {
                cur = n ^ ((cur >> shift) & mask);
            }
            return(cur);
        }
        public static (UInt a, UInt b) PyGetPossibleOutputs(double d)
        {
            const double k     = 1UL << 53;              // Maximum value of a 53-bit number + 1
            const uint   bMask = (1U << 26) - 1;         // A binary number containing 26 1s, used to extract b from d (the last 26 bits)
            ULong        n     = (ULong)(d * k);         // Convert d back into a long by multiplying it by its max value + 1
            UInt         b     = (uint)(n & bMask) << 6; // Use bitwise AND to get b from n, then shift the bits back to the correct locations
            UInt         a     = (uint)(n >> 26) << 5;   // The rest of the bits are a, so just use some shifting, then shift the bits back to the correct locations

            return(a, b);                                // Keep in mind that some bits were lost by PyRandom. Those bits don't matter to the algorithm though, so anything can go there and you'd get the same result
        }
        public double PyRandom()
        {
            // Why 53-bit numbers..?
            UInt         a = this.ExtractNumber() >> 5; // Remove 5 bits, 27-bit number
            UInt         b = this.ExtractNumber() >> 6; // Remove 6 bits, 26-bit number
            const double k = 1UL << 53;                 // Maximum value of a 53-bit number + 1
            ULong        n = ((ulong)a << 26) + b;      // Create a 53-bit number in the form ab

            return(n / k);                              // Turn n into a fraction
        }
        public uint ExtractNumber()
        {
            if (this._index >= MersenneTwister.N)
            {
                if (this._index > MersenneTwister.N)
                {
                    throw new Exception("Generator was never seeded");
                }
                this.Twist();
            }

            UInt y = this._mt[this._index++];

            y = y ^ ((y >> MersenneTwister.U) & MersenneTwister.D);
            y = y ^ ((y << MersenneTwister.S) & MersenneTwister.B);
            y = y ^ ((y << MersenneTwister.T) & MersenneTwister.C);
            y = y ^ (y >> MersenneTwister.L);

            return(y);
        }
        // Brute force the factor
        private static UInt GetFactorFromProduct(UInt product)
        {
            IEnumerable <BigInteger> Multiples(BigInteger factor, BigInteger maxMultiple)
            {
                maxMultiple /= factor;
                for (BigInteger i = 0; i <= maxMultiple; i++)
                {
                    yield return(factor * i);
                }
            }

            const uint mask = 0xFFFFFFFF;

            foreach (BigInteger multiple in Multiples(0x5D588B65U, (ulong)0x5D588B65U * 0xFFFFFFFF).Where(m => (m & mask) == product))
            {
                return((uint)(multiple / 0x5D588B65U));
            }

            throw new Exception("Failed to find a factor");
        }
 private static UInt GetStateFromProduct(UInt product, UInt curState) => product ^ curState;
 private static UInt GetProductFromFactor(UInt factor) => factor * 0x5D588B65U;
        //////

        private static UInt GetFactorFromKey(UInt key) => key ^ (key >> 30);
 private static UInt GetKeyFromFactor(UInt factor) => factor ^ (factor >> 30);
        //////

        private static UInt GetOriginalStateFromProduct(UInt state, UInt product) => state ^ product;
 public static UInt Temper(UInt n, int shift, UInt mask) => n ^ ((n << shift) & mask);
 public static UInt Temper(UInt n, int shift) => n ^ (n >> shift);
        /// <summary>Returns an initKey for the current state. If the first key value is incorrect, try a different <see cref="tryKey"/> to see if that works.</summary>
        /// <param name="tryKey">First initKey value</param>
        /// <param name="keyWidth">Width of the initKey. Only the first N values matter in it</param>
        /// <returns>A (probably working) initKey</returns>
        public UInt[] PyGetInitKey(uint tryKey = 0, uint keyWidth = MersenneTwister.N)
        {
            UInt[] initKey = new UInt[keyWidth];
            UInt[] mt      = this._mt.ToArray();

            uint j = 0;
            uint k;

            // Emulate setting the state without actually setting it. This can be done mathematically
            for (k = Math.Max(MersenneTwister.N, (uint)initKey.Length); k > 0; k--)
            {
                j++;
                if (j >= initKey.Length)
                {
                    j = 0;
                }
            }

            // Reverse the process

            // This is the value for mt[0] after the first loop and throughout the second loop
            mt[0] = mt[MersenneTwister.N - 1];

            // Undo the last 'i++' that occured to set i to the last modified index (1)
            uint i = 1;

            // Undo second for loop
            // Hilariously enough, this looks almost exactly the same as the process used to get the state from the initKey
            for (k = 1; k < MersenneTwister.N; k++)
            {
                mt[i] += i;
                mt[i]  = mt[i] ^ (mt[i - 1] ^ (mt[i - 1] >> 30)) * 0x5D588B65U;
                i--;

                if (i == 0)
                {
                    i = MersenneTwister.N - 1;
                }
            }

            // This is the value for mt[0]
            mt[0] = mt[MersenneTwister.N - 1];

            i = 1;
            j--;
            if (j > initKey.Length)
            {
                j = (uint)initKey.Length - 1;
            }

            // Undo first for loop and grab the initKey
            UInt[] origMt = new MersenneTwister(0x12BD6AAU)._mt;
            for (k = 1; k < Math.Max(MersenneTwister.N, (uint)initKey.Length); k++)
            {
                if (k == 1)
                {
                    // initKey[j] is actually a function of initKey[j0]. There is not a single solution for it, but many solutions (finite due to integer restriction).
                    const uint j2     = 0; // j when the first loop starts
                    UInt       mtPrev = (origMt[i] ^ (origMt[i - 1] ^ origMt[i - 1] >> 30) * 0x19660DU) + tryKey + j2;
                    initKey[j] = mt[i] - (mtPrev ^ (mt[i - 1] ^ mt[i - 1] >> 30) * 0x19660DU) - j;
                    mt[i]      = mtPrev;
                }
                else
                {
                    initKey[j] = mt[i] - (origMt[i] ^ (mt[i - 1] ^ mt[i - 1] >> 30) * 0x19660DU) - j;
                    mt[i]      = origMt[i];
                }

                i--;
                j--;

                if (i == 0)
                {
                    mt[0] = origMt[0];
                    i     = MersenneTwister.N - 1;
                }

                if (j == uint.MaxValue)
                {
                    j = (uint)initKey.Length - 1;
                }
            }

            return(initKey);
        }