Attribute VB_Name = "RandomGenerator"

'This is a deterministic random generator since
'  you can reset it with a seed at any time

'RandomMatrix(n) >= 0
'Otherwise mod will be non deterministic
Dim RandomMatrix(19) As Long
Dim CounterA As Long
Dim CounterB As Long

Option Explicit

Public Sub Random_Reset(Seed As Integer)
    Dim NegativeSeed As Long
    If Seed < 0 Then
        Seed = -Seed
        NegativeSeed = 645
    ElseIf Seed >= 10000 Then
        Seed = (Seed Mod 10000) Xor 8975
        NegativeSeed = 354
    Else
        NegativeSeed = 76
    End If
    CounterA = Seed Mod 183553
    CounterB = (Seed Mod 36575) + 477976
    RandomMatrix(0) = (Seed Mod 79346586) + 3786458
    RandomMatrix(1) = ((Seed * 2) Mod 863) + 6257674
    RandomMatrix(2) = (Seed Mod 3658686) + 864545
    RandomMatrix(3) = ((Seed * 3) Mod 3965) + 376745
    RandomMatrix(4) = (Seed Mod 5746846) + 9836453
    RandomMatrix(5) = (Seed Mod 3376544) + 2978364
    RandomMatrix(6) = ((Seed * 2) Mod 8563) + 5067634
    RandomMatrix(7) = ((Seed * 3) Mod (3456 + NegativeSeed)) + 945375
    RandomMatrix(8) = (Seed Mod 4584763) + 397685
    RandomMatrix(9) = (Seed Mod 8767556) + 594542
    RandomMatrix(10) = ((Seed * 2) Mod 3575) + 676548
    RandomMatrix(11) = (Seed Mod 264586) + 3984644
    RandomMatrix(12) = (Seed Mod 568768) + 6556673
    RandomMatrix(13) = ((Seed * 3) Mod 1764) + 3944565
    RandomMatrix(14) = ((Seed * 2) Mod 3863) + 8854556
    RandomMatrix(15) = (Seed Mod 357) + 3566476
    RandomMatrix(16) = ((Seed * 3) Mod 724558) + 4657345
    RandomMatrix(17) = (Seed Mod 558786) + 9487665
    RandomMatrix(18) = ((Seed * 2) Mod (2976865 + NegativeSeed)) + 7857256
    RandomMatrix(19) = ((Seed * 3) Mod 5824584) + 3454867
    Call Random_GetNumber(4776, 8475674)
    Call Random_GetNumber(874, 6898435)
End Sub

Private Sub Shuffle()
    Dim I As Long
    Dim A As Long
    Dim B As Long
    Dim Swap As Long
    For I = 1 To 10
        'Count
        CounterA = (CounterA + 5) Mod 484534
        CounterB = (CounterB + 3) Mod 642675
        
        'Xor
        A = (RandomMatrix(2) + CounterA) Mod 20
        B = (RandomMatrix(14) + CounterB) Mod 20
        RandomMatrix(A) = (RandomMatrix(A) Xor RandomMatrix(B)) Mod 7385763
        
        'Add
        A = (RandomMatrix(7) + CounterA) Mod 20
        B = (RandomMatrix(5) + CounterB) Mod 20
        RandomMatrix(A) = (RandomMatrix(A) + RandomMatrix(B)) Mod 8354864
        
        'Swap
        A = (RandomMatrix(4) + CounterA) Mod 20
        B = (RandomMatrix(8) + CounterB) Mod 20
        Swap = RandomMatrix(A)
        RandomMatrix(A) = RandomMatrix(B)
        RandomMatrix(B) = Swap
    Next I
End Sub

'Use this function for random integers
'It works well with large numbers but it might
'  become predictable for ranges over 1000000
Public Function Random_GetNumber(Min As Long, Max As Long) As Long
    Dim I As Long
    Debug.Assert Min <= Max
    Shuffle
    Random_GetNumber = 0
    For I = 0 To 19
        Random_GetNumber = (Random_GetNumber + RandomMatrix(I)) Mod ((Max - Min) + 1)
        Debug.Assert Random_GetNumber >= 0
    Next I
    Random_GetNumber = Random_GetNumber + Min
    Debug.Assert Random_GetNumber >= Min And Random_GetNumber <= Max
End Function

Public Function Random_GetFloat(Min As Single, Max As Single) As Single
    Random_GetFloat = ((Random_GetNumber(0, 10000) / 10000) * (Max - Min)) + Min
End Function
