- Joined
- Sep 26, 2009
- Messages
- 9,534
I fail to see why one wouldn’t just use the built-in GetRandomInt and GetRandomReal. If JASS didn’t already have those functions, then this resource would have a purpose.
/*
This is a linear congruential generator in vJass. You can have different setups and seeds in tandem.
This wiki article contains a good list of numbers to plug in:
https://en.wikipedia.org/wiki/Linear_congruential_generator#cite_note-Steele20-2
These kind of generators can generate psuedo random numbers without repeating until it reaches the period.
The period is just a term used to denote the number where the generator will reset and patterns can emerge if
this period is too small.
The maximum a period can be is based off of the .mod parameter. The period can never exceed the .mod, but it can be less
than the .mod if you have bad parameters - hence the warning below.
Combining two generators can increase the period by an order of magnitude of 9, meaning you can have really, really long periods
without patterns emerging. (Like 5,290,000,000,000,000,000 long, as seen in the example. This may seem impossible in 32 bit, but
there is some seriously math cool going on here)
This can be useful for a number of things, for example:
1. Creating seed based foliage
2. Proceedural generation
3. Using it like a weird noise algorithm https://en.wikipedia.org/wiki/RANDU
4. Async usage - just be careful of thread limiting locally
5. Random number usage without affecting vanilla gameplay RNG
WARNING: Plugging in random numbers will give terrible results! Refer to the numbers list in the wiki at the top for
consistent RNG.
Methods:
1. Create (seed, multiplier, modulus, increment) - returns your new RNG table
2. Random - returns a number between 0 and 1
3. Real (low bound range, high bound range) - returns within the range provided
4. Int - same as above
Combined
Functions:
1. RandomC (RNG 1, RNG 2) - combines two RNGs and returns a number between 0 and 1
2. RandomRealC( RNG 1, RNG 2, low bound range, high bound range) - returns within the range provided
3. RandomIntC - same as above
*/
library RandomNumberGenerator
struct RNG
integer seed
integer mult
integer mod
integer inc
static method create takes integer newSeed, integer newMult, integer newMod, integer newInc returns RNG
local RNG this = RNG.allocate()
set .seed = newSeed
set .mult = newMult
set .mod = newMod
set .inc = newInc
return this
endmethod
method push takes nothing returns integer
local integer d = .seed * .mult + .inc
local integer m = d - (d / .mod) * .mod
if m < 0 then
set m = m + .mod
endif
set .seed = m
return 0
endmethod
method Random takes nothing returns real
return .push() + I2R(.seed) / .mod
endmethod
method Real takes real lowBound, real highBound returns real
return .Random() * (highBound - lowBound) + lowBound
endmethod
method Int takes integer lowBound, integer highBound returns integer
return MathRound(.Random() * (highBound - lowBound) + lowBound)
endmethod
endstruct
//Combined RNG
function RandomC takes RNG rng1, RNG rng2 returns real
local integer d = rng1.push() + rng2.push() + rng1.seed - rng2.seed
local integer m = IMaxBJ(rng1.mod,rng2.mod)
local integer r = d - (d / m) * m
if r > 0 then
return I2R(r) / m
elseif r < 0 then
return I2R(r) / m + 1
else
return I2R(m - 1) / m
endif
endfunction
function RandomRealC takes RNG rng1, RNG rng2, real lowBound, real highBound returns real
return RandomC(rng1,rng2) * (highBound - lowBound) + lowBound
endfunction
function RandomIntC takes RNG rng1, RNG rng2, integer lowBound, integer highBound returns integer
return MathRound(RandomC(rng1,rng2) * (highBound - lowBound) + lowBound)
endfunction
endlibrary
do
local this, d, m
RNG = {seed = 0, mult = 0, mod = 0, inc = 0}
function RNG:new(seed, mult, mod, inc)
local this = {}
setmetatable(this,self)
self.__index = self
self.seed = seed
self.mult = mult
self.mod = mod
self.inc = inc
self.div = 1/mod
return this
end
function RNG:push()
d = self.seed * self.mult + self.inc
m = d - math.floor(d * self.div) * self.mod
if m < 0 then
m = m + self.mod
end
self.seed = m
end
function RNG:random(low,high)
self:push()
m = self.seed * self.div
if low then
if high then
m = m*(high-low)+low
else
m = m *(low-1) + 1
end
if math.type(low) == "integer" then
m = m>=0 and math.floor(m+0.5) or math.ceil(m-0.5)
end
end
return m
end
end