Big Robot Games - Indie Dev Blog Edition

Somewhere for me to post my musings on Indie Development, Cryptocurrencies and whatever else strikes my fancy.

Mersenne Twister

This is an implementation of the Mersenne Twister random number generator, written in VB.NET. (I had a C# version laying around at one point, but I may have deleted it. This one works exactly the same, and implements the same algorithm.)

This is what I use in Heroic Adventure! (HA!) and have recently added it to my Cellular Automata project as well. It's a nice fast substitute for System.Random, with a much longer period before predictable repeating patterns.

'
' An implementation of the Mersenne Twister algorithm (MT19937), developed
' with reference to the C code written by Takuji Nishimura and Makoto Matsumoto
' (
http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html).
'
' This code is free to use for any pupose.
'

Option Strict On

'''
''' A random number generator with a uniform distribution using the Mersenne
''' Twister algorithm.
'''
Public Class MersenneTwister
 Private Const N As Integer = 624
 Private Const M As Integer = 397
 Private Const MATRIX_A As UInteger = &H9908B0DFUI
 Private Const UPPER_MASK As UInteger = &H80000000UI
 Private Const LOWER_MASK As UInteger = &H7FFFFFFFUI

 Private mt(N - 1) As UInteger
 Private mti As Integer = N + 1

 ''' <summary>
 ''' Create a new Mersenne Twister random number generator.
 ''' </summary>
 Public Sub New()
  Me.New(CUInt(Date.Now.Millisecond))
 End Sub

 ''' <summary>
 ''' Create a new Mersenne Twister random number generator with a
 ''' particular seed.
 ''' </summary>
 ''' <param name="seed">The seed for the generator.</param>
 <CLSCompliant(False)> _
 Public Sub New(ByVal seed As UInteger)
  mt(0) = seed
  For mti = 1 To N - 1
   mt(mti) = CUInt((1812433253UL * (mt(mti - 1) Xor (mt(mti - 1) >> 30)) + CUInt(mti)) And &HFFFFFFFFUL)
  Next
 End Sub

 ''' <summary>
 ''' Create a new Mersenne Twister random number generator with a
 ''' particular initial key.
 ''' </summary>
 ''' <param name="initialKey">The initial key.</param>
 <CLSCompliant(False)> _
 Public Sub New(ByVal initialKey() As UInteger)
  Me.New(19650218UI)

  Dim i, j, k As Integer
  i = 1 : j = 0
  k = CInt(IIf(N > initialKey.Length, N, initialKey.Length))

  For k = k To 1 Step -1
   mt(i) = CUInt(((mt(i) Xor ((mt(i - 1) Xor (mt(i - 1) >> 30)) * 1664525UL)) + initialKey(j) + CUInt(j)) And &HFFFFFFFFUI)
   i += 1 : j += 1
   If i >= N Then mt(0) = mt(N - 1) : i = 1
   If j >= initialKey.Length Then j = 0
  Next

  For k = N - 1 To 1 Step -1
   mt(i) = CUInt(((mt(i) Xor ((mt(i - 1) Xor (mt(i - 1) >> 30)) * 1566083941UL)) - CUInt(i)) And &HFFFFFFFFUI)
   i += 1
   If i >= N Then mt(0) = mt(N - 1) : i = 1
  Next

  mt(0) = &H80000000UI
 End Sub

 ''' <summary>
 ''' Generates a random number between 0 and System.UInt32.MaxValue.
 ''' </summary>
 <CLSCompliant(False)> _
 Public Function NextUInt32() As UInteger
  Dim y As UInteger
  Static mag01() As UInteger = {&H0UI, MATRIX_A}

  If mti >= N Then
   Dim kk As Integer

   Debug.Assert(mti <> N + 1, "Failed initialization")

   For kk = 0 To N - M - 1
    y = (mt(kk) And UPPER_MASK) Or (mt(kk + 1) And LOWER_MASK)
    mt(kk) = mt(kk + M) Xor (y >> 1) Xor mag01(CInt(y And &H1))
   Next

   For kk = kk To N - 2
    y = (mt(kk) And UPPER_MASK) Or (mt(kk + 1) And LOWER_MASK)
    mt(kk) = mt(kk + (M - N)) Xor (y >> 1) Xor mag01(CInt(y And &H1))
   Next

   y = (mt(N - 1) And UPPER_MASK) Or (mt(0) And LOWER_MASK)
   mt(N - 1) = mt(M - 1) Xor (y >> 1) Xor mag01(CInt(y And &H1))

   mti = 0
  End If

  y = mt(mti)
  mti += 1

  ' Tempering
  y = y Xor (y >> 11)
  y = y Xor ((y << 7) And &H9D2C5680UI)
  y = y Xor ((y << 15) And &HEFC60000UI)
  y = y Xor (y >> 18)

  Return y
 End Function

 ''' <summary>
 ''' Generates a random integer between 0 and System.Int32.MaxValue.
 ''' </summary>
 Public Function [Next]() As Integer
  Return CInt(NextUInt32() >> 1)
 End Function

 ''' <summary>
 ''' Generates a random integer between 0 and maxValue.
 ''' </summary>
 ''' <param name="maxValue">The maximum value. Must be greater than zero.</param>
 Public Function [Next](ByVal maxValue As Integer) As Integer
  Return [Next](0, maxValue)
 End Function

 ''' <summary>
 ''' Generates a random integer between minValue and maxValue.
 ''' </summary>
 ''' <param name="maxValue">The lower bound.</param>
 ''' <param name="minValue">The upper bound.</param>
 Public Function [Next](ByVal minValue As Integer, ByVal maxValue As Integer) As Integer
  Return CInt(Math.Floor((maxValue - minValue + 1) * NextDouble() + minValue))
 End Function

 ''' <summary>
 ''' Generates a random floating point number between 0 and 1.
 ''' </summary>
 Public Function NextDouble() As Double
  Return NextUInt32() * (1.0 / 4294967295.0)
 End Function
End Class
 

Loading