0
0
Fork 0
mirror of https://gitlab.com/Oreolek/salet-module.git synced 2024-06-28 21:05:03 +03:00

Fast PRNG instead of the slow Mersenne Twister

This commit is contained in:
Alexander Yakovlev 2016-09-10 11:24:08 +07:00
parent 961b0a936a
commit 70c8d2c705
2 changed files with 32 additions and 130 deletions

View file

@ -1,149 +1,53 @@
###
This implementation of the Mersenne Twister is a port of the JavaScript
version by Y. Okada. The JavaScript version was itself a port of a
C implementation, by Takuji Nishimura and Makoto Matsumoto.
Fast performance pseudo random number generator.
CoffeeScript port by: Jamis Buck <jamis@jamisbuck.org>
License: Public domain, baby. Knock yourself out.
Not the cryptographic-level randomness, but enough for most games.
The original CoffeeScript sources are always available on GitHub:
http://github.com/jamis/csmazes
Code from CoffeeScript Cookbook:
https://coffeescript-cookbook.github.io/chapters/math/generating-predictable-random-numbers
###
class Random
N: 624
M: 397
MATRIX_A: 0x9908b0df
UPPER_MASK: 0x80000000
LOWER_MASK: 0x7fffffff
constructor: (@seed) ->
@multiplier = 1664525
@modulo = 4294967296 # 2**32-1;
@offset = 1013904223
unless @seed? && 0 <= seed < @modulo
@seed = (new Date().valueOf() * new Date().getMilliseconds()) % @modulo
constructor: (seed) ->
@mt = new Array(@N)
@setSeed seed
# sets new seed value
seed: (seed) ->
@seed = seed
# makes the argument into an unsigned integer, if it is not already one
unsigned32: (n1) -> if n1 < 0 then (n1 ^ @UPPER_MASK) + @UPPER_MASK else n1
getSeed: () ->
return @seed
# emulates underflow of subtracting two 32-bit unsigned integers. both arguments
# must be non-negative 32-bit integers.
subtraction32: (n1, n2) ->
if n1 < n2
@unsigned32((0x100000000 - (n2 - n1)) % 0xffffffff)
else
n1 - n2
# return a random integer 0 <= n < @modulo
randn: ->
# new_seed = (a * seed + c) % m
@seed = (@multiplier*@seed + @offset) % @modulo
# emulates overflow of adding two 32-bit integers. both arguments must be
# non-negative 32-bit integers.
addition32: (n1, n2) -> @unsigned32((n1 + n2) & 0xffffffff)
# return a random float 0 <= f < 1.0
randf: ->
this.randn() / @modulo
# emulates overflow of multiplying two 32-bit integers. both arguments must
# be non-negative 32-bit integers.
multiplication32: (n1, n2) ->
sum = 0
for i in [0...32]
if ((n1 >>> i) & 0x1)
sum = @addition32(sum, @unsigned32(n2 << i))
sum
# return a random int 0 <= f < n
rand: (n) ->
Math.floor(this.randf() * n)
setSeed: (seed) ->
if !seed || typeof seed == "number"
@seedWithInteger seed
else
@seedWithArray seed
defaultSeed: ->
currentDate = new Date()
currentDate.getMinutes() * 60000 + currentDate.getSeconds() * 1000 + currentDate.getMilliseconds()
seedWithInteger: (seed) ->
@seed = seed ? @defaultSeed()
@mt[0] = @unsigned32(@seed & 0xffffffff)
@mti = 1
while @mti < @N
@mt[@mti] = @addition32(
@multiplication32(1812433253, @unsigned32(@mt[@mti-1] ^ (@mt[@mti-1] >>> 30))),
@mti)
@mti[@mti] = @unsigned32(@mt[@mti] & 0xffffffff)
@mti++
seedWithArray: (key) ->
@seedWithInteger 19650218
i = 1
j = 0
k = if @N > key.length then @N else key.length
while k > 0
_m = @multiplication32(@unsigned32(@mt[i-1] ^ (@mt[i-1] >>> 30)), 1664525)
@mt[i] = @addition32(@addition32(@unsigned32(@mt[i] ^ _m), key[j]), j)
@mt[i] = @unsigned32(@mt[i] & 0xffffffff)
i++
j++
if i >= @N
@mt[0] = @mt[@N-1]
i = 1
j = 0 if j >= key.length
k--
k = @N - 1
while k > 0
@mt[i] = @subtraction32(
@unsigned32(@mt[i] ^ @multiplication32(@unsigned32(@mt[i-1] ^ (@mt[i-1] >>> 30)), 1566083941)), i)
@mt[i] = @unsigned32(@mt[i] & 0xffffffff)
i++
if i >= @N
@mt[0] = @mt[@N-1]
i = 1
@mt[0] = 0x80000000
nextInteger: (upper) ->
return 0 if (upper ? 1) < 1
mag01 = [0, @MATRIX_A]
if @mti >= @N
kk = 0
while kk < @N - @M
y = @unsigned32((@mt[kk] & @UPPER_MASK) | (@mt[kk+1] & @LOWER_MASK))
@mt[kk] = @unsigned32(@mt[kk+@M] ^ (y >>> 1) ^ mag01[y & 0x1])
kk++
while kk < @N-1
y = @unsigned32((@mt[kk] & @UPPER_MASK) | (@mt[kk+1] & @LOWER_MASK))
@mt[kk] = @unsigned32(@mt[kk+@M-@N] ^ (y >>> 1) ^ mag01[y & 0x1])
kk++
y = @unsigned32((@mt[@N-1] & @UPPER_MASK) | (@mt[0] & @LOWER_MASK))
@mt[@N-1] = @unsigned32(@mt[@M-1] ^ (y >>> 1) ^ mag01[y & 0x1])
@mti = 0
y = @mt[@mti++]
y = @unsigned32(y ^ (y >>> 11))
y = @unsigned32(y ^ ((y << 7) & 0x9d2c5680))
y = @unsigned32(y ^ ((y << 15) & 0xefc60000))
@unsigned32(y ^ (y >>> 18)) % (upper ? 0x100000000)
# return a random int min <= f < max
randRange: (min, max) ->
min + this.rand(max-min)
randomInt: (upper) ->
@nextInteger(upper)
nextFloat: -> @nextInteger() / 0xffffffff
nextBoolean: -> @nextInteger() % 2 == 0
@rand(upper)
# Returns the result of rolling *n* dice with *dx* sides, and adding *plus*.
dice: (n, dx, plus) ->
result = 0
for i in [0..n]
console.log i
result += @nextInteger(1, dx)
result += 1 + @randRange(1,dx)
if (plus)
result += plus
result

View file

@ -417,10 +417,8 @@ class Salet
console.error err
else
currentDate = new Date()
@progress.seed = currentDate.getMinutes() * 60000
@progress.seed += currentDate.getSeconds() * 1000
@progress.seed += currentDate.getMilliseconds()
@rnd = new Random(@progress.seed)
@rnd = new Random()
@progress.seed = @rnd.getSeed()
@progress.sequence = [{link:@start, when:0}]