Module:Pyrandom

From Glolf Wiki
Jump to navigation Jump to search

Documentation for this module may be created at Module:Pyrandom/doc

local bit32 = require "bit32"
local mt = require "Module:Mt19937ar"

function bit_length(n)
	local l = 0
	while n > 0 do
		l = l + 1
		n = bit32.rshift(n, 1)
	end
	return l
end

local pyrandom = {}
function pyrandom.new(str)
	local instance = {}

	function instance:seed(str)
		local seed = ""
		for i = 1, #str do
			seed = seed .. string.format('%02x', string.byte(str, i))
		end
		seed = seed .. mw.hash.hashValue("sha512", str)
		seed = string.rep('0', (8 - (#seed % 8)) % 8) .. seed
		seed_array = {}
		for i = #seed, 1, -8 do
			table.insert(seed_array, tonumber(string.sub(seed, i-7, i), 16))
		end
		local mt = mt.new()
		mt:init_by_array(seed_array)
		return mt
	end

	local rand = instance:seed(str)

	function instance:random()
		return rand:genrand_res53()
	end

	function instance:getrandbits(k)
		if k == 0 then
			return 0
		end

		return bit32.rshift(rand:genrand_int32(), (32 - k))
	end

	function instance:_randbelow(n)
		if n == 0 then
			return 0
		end
		local k = bit_length(n)
		local r = self:getrandbits(k)
		while r >= n do
			r = self:getrandbits(k)
		end
		return r
	end

	function instance:randrange(start, stop)
		if (stop == nil) then
			return self:_randbelow(start)
		end

		return start + self:_randbelow(stop - start)
	end

	function instance:choice(array)
		local r = self:_randbelow(#array)
		return array[r + 1]
	end

	local gauss_next = nil
	function instance:gauss(mu, sigma)
		local z = gauss_next
		gauss_next = nil
		if z == nil then
			local x2pi = self:random() * math.pi * 2
			local g2rad = math.sqrt(-2.0 * math.log(1.0 - self:random()))
			z = math.cos(x2pi) * g2rad
			gauss_next = math.sin(x2pi) * g2rad
		end
		return mu + z * sigma
	end

	return instance
end

return pyrandom