233 lines
5.3 KiB
Lua
233 lines
5.3 KiB
Lua
--[[----------------------------------------
|
|
Random
|
|
Not all of this is mine
|
|
------------------------------------------]]
|
|
--[[------------------------------------
|
|
RandomLua v0.3.1
|
|
Pure Lua Pseudo-Random Numbers Generator
|
|
Under the MIT license.
|
|
copyright(c) 2011 linux-man
|
|
--]]------------------------------------
|
|
|
|
local math_floor = math.floor
|
|
|
|
local function normalize(n)
|
|
return n % 0x80000000
|
|
end
|
|
|
|
local function bit_and(a, b)
|
|
local r = 0
|
|
local m = 0
|
|
for m = 0, 31 do
|
|
if (a % 2 == 1) and (b % 2 == 1) then r = r + 2^m end
|
|
if a % 2 ~= 0 then a = a - 1 end
|
|
if b % 2 ~= 0 then b = b - 1 end
|
|
a = a / 2 b = b / 2
|
|
end
|
|
return normalize(r)
|
|
end
|
|
|
|
local function bit_or(a, b)
|
|
local r = 0
|
|
local m = 0
|
|
for m = 0, 31 do
|
|
if (a % 2 == 1) or (b % 2 == 1) then r = r + 2^m end
|
|
if a % 2 ~= 0 then a = a - 1 end
|
|
if b % 2 ~= 0 then b = b - 1 end
|
|
a = a / 2 b = b / 2
|
|
end
|
|
return normalize(r)
|
|
end
|
|
|
|
local function bit_xor(a, b)
|
|
local r = 0
|
|
local m = 0
|
|
for m = 0, 31 do
|
|
if a % 2 ~= b % 2 then r = r + 2^m end
|
|
if a % 2 ~= 0 then a = a - 1 end
|
|
if b % 2 ~= 0 then b = b - 1 end
|
|
a = a / 2 b = b / 2
|
|
end
|
|
return normalize(r)
|
|
end
|
|
|
|
local function seed()
|
|
return normalize(os.time())
|
|
end
|
|
|
|
--Mersenne twister
|
|
local mersenne_twister = {}
|
|
mersenne_twister.__index = mersenne_twister
|
|
|
|
function mersenne_twister:randomseed(s)
|
|
if not s then s = seed() end
|
|
self.mt[0] = normalize(s)
|
|
for i = 1, 623 do
|
|
self.mt[i] = normalize(0x6c078965 * bit_xor(self.mt[i-1], math_floor(self.mt[i-1] / 0x40000000)) + i)
|
|
end
|
|
end
|
|
|
|
function mersenne_twister:random(a, b)
|
|
local y
|
|
if self.index == 0 then
|
|
for i = 0, 623 do
|
|
y = self.mt[(i + 1) % 624] % 0x80000000
|
|
self.mt[i] = bit_xor(self.mt[(i + 397) % 624], math_floor(y / 2))
|
|
if y % 2 ~= 0 then self.mt[i] = bit_xor(self.mt[i], 0x9908b0df) end
|
|
end
|
|
end
|
|
y = self.mt[self.index]
|
|
y = bit_xor(y, math_floor(y / 0x800))
|
|
y = bit_xor(y, bit_and(normalize(y * 0x80), 0x9d2c5680))
|
|
y = bit_xor(y, bit_and(normalize(y * 0x8000), 0xefc60000))
|
|
y = bit_xor(y, math_floor(y / 0x40000))
|
|
self.index = (self.index + 1) % 624
|
|
if not a then return y / 0x80000000
|
|
elseif not b then
|
|
if a == 0 then return y
|
|
else return 1 + (y % a)
|
|
end
|
|
else
|
|
return a + (y % (b - a + 1))
|
|
end
|
|
end
|
|
|
|
local function twister(s)
|
|
local temp = {}
|
|
setmetatable(temp, mersenne_twister)
|
|
temp.mt = {}
|
|
temp.index = 0
|
|
temp:randomseed(s)
|
|
return temp
|
|
end
|
|
|
|
--Linear Congruential Generator
|
|
local linear_congruential_generator = {}
|
|
linear_congruential_generator.__index = linear_congruential_generator
|
|
|
|
function linear_congruential_generator:random(a, b)
|
|
local y = (self.a * self.x + self.c) % self.m
|
|
self.x = y
|
|
if not a then return y / 0x10000
|
|
elseif not b then
|
|
if a == 0 then return y
|
|
else return 1 + (y % a) end
|
|
else
|
|
return a + (y % (b - a + 1))
|
|
end
|
|
end
|
|
|
|
function linear_congruential_generator:randomseed(s)
|
|
if not s then s = seed() end
|
|
self.x = normalize(s)
|
|
end
|
|
|
|
local function lcg(s, r)
|
|
local temp = {}
|
|
setmetatable(temp, linear_congruential_generator)
|
|
temp.a, temp.c, temp.m = 1103515245, 12345, 0x10000 --from Ansi C
|
|
if r then
|
|
if r == 'nr' then temp.a, temp.c, temp.m = 1664525, 1013904223, 0x10000 --from Numerical Recipes.
|
|
elseif r == 'mvc' then temp.a, temp.c, temp.m = 214013, 2531011, 0x10000 end--from MVC
|
|
end
|
|
temp:randomseed(s)
|
|
return temp
|
|
end
|
|
|
|
-- Multiply-with-carry
|
|
local multiply_with_carry = {}
|
|
multiply_with_carry.__index = multiply_with_carry
|
|
|
|
function multiply_with_carry:random(a, b)
|
|
local m = self.m
|
|
local t = self.a * self.x + self.c
|
|
local y = t % m
|
|
self.x = y
|
|
self.c = math_floor(t / m)
|
|
if not a then return y / 0x10000
|
|
elseif not b then
|
|
if a == 0 then return y
|
|
else return 1 + (y % a) end
|
|
else
|
|
return a + (y % (b - a + 1))
|
|
end
|
|
end
|
|
|
|
function multiply_with_carry:randomseed(s)
|
|
if not s then s = seed() end
|
|
self.c = self.ic
|
|
self.x = normalize(s)
|
|
end
|
|
|
|
local function mwc(s, r)
|
|
local temp = {}
|
|
setmetatable(temp, multiply_with_carry)
|
|
temp.a, temp.c, temp.m = 1103515245, 12345, 0x10000 --from Ansi C
|
|
if r then
|
|
if r == 'nr' then temp.a, temp.c, temp.m = 1664525, 1013904223, 0x10000 --from Numerical Recipes.
|
|
elseif r == 'mvc' then temp.a, temp.c, temp.m = 214013, 2531011, 0x10000 end--from MVC
|
|
end
|
|
temp.ic = temp.c
|
|
temp:randomseed(s)
|
|
return temp
|
|
end
|
|
-- Little bind for the methods: My code starts
|
|
local randomGen={}
|
|
randomGen.__index=randomGen
|
|
function randomGen:new(s)
|
|
local temp={}
|
|
setmetatable(temp,randomGen)
|
|
temp[1]=twister()
|
|
temp[2]=lcg()
|
|
temp[3]=mwc()
|
|
temp.pos=1
|
|
for i=1,3 do
|
|
temp[i]:randomseed(s)
|
|
end
|
|
return temp
|
|
end
|
|
function randomGen:randomseed(s)
|
|
self.pos=1
|
|
self[1]:randomseed(s)
|
|
self[2]:randomseed(s)
|
|
self[3]:randomseed(s)
|
|
end
|
|
function randomGen:randomInt(a,b)
|
|
local t=self[self.pos]:random(a,b)
|
|
self.pos=self.pos+1
|
|
if self.pos>3 then
|
|
self.pos=1
|
|
end
|
|
return t
|
|
end
|
|
function randomGen:newND(a,b,s)
|
|
if not(a) or not(b) then error('You must include a range!') end
|
|
local temp=randomGen:new(s)
|
|
temp.a=a
|
|
temp.b=b
|
|
temp.range=b-a+1
|
|
temp.dups={no=0}
|
|
function temp:nextInt()
|
|
local t=self:randomInt(self.a,self.b)
|
|
if self.dups[t]==nil then
|
|
self.dups[t]=true
|
|
self.dups.no=self.dups.no+1
|
|
else
|
|
return self:nextInt()
|
|
end
|
|
if self.dups.no==self.range then
|
|
function self:nextInt()
|
|
return 1,true
|
|
end
|
|
return t
|
|
else
|
|
return t
|
|
end
|
|
end
|
|
function temp:nextIInt()
|
|
return function() return self:nextInt() end
|
|
end
|
|
return temp
|
|
end
|
|
return randomGen
|