Module:Grind/dist

From Fallen London Wiki

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

local p = {}

local util = require('Module:Grind/util')

-- == Distribution manipulations ==

-- Multiplies effect distribution by a constant.
function p.effect_mul(effect, multiplier)
	local eff = {}
	if multiplier == 0 then
		return eff
	end
	for resource, dist in pairs(effect) do
		eff[resource] = {}
		for delta, prob in pairs(dist) do
			if eff[resource][delta * multiplier] == nil then
				eff[resource][delta * multiplier] = 0
			end
			eff[resource][delta * multiplier] = eff[resource][delta * multiplier] + prob
		end
	end
	return eff
end

-- Computes the sum of effect distributions.
function p.effect_sum(eff1, eff2)
	local eff = {}
	local resources = {}
	for resource, _ in pairs(eff1) do
		resources[resource] = true
	end
	for resource, _ in pairs(eff2) do
		resources[resource] = true
	end
	for resource, _ in pairs(resources) do
		local dist1 = eff1[resource]
		local dist2 = eff2[resource]
		eff[resource] = {}
		if dist1 ~= nil and dist2 ~= nil then
			for delta1, prob1 in pairs(dist1) do
				for delta2, prob2 in pairs(dist2) do
					local delta = delta1 + delta2
					local prob = prob1 * prob2
					-- check for NaN
					if delta == delta then
						if eff[resource][delta] == nil then
							eff[resource][delta] = 0
						end
						eff[resource][delta] = eff[resource][delta] + prob
					end
				end
			end
		elseif dist1 ~= nil then
			eff[resource] = dist1
		else
			eff[resource] = dist2
		end
	end
	return eff
end

-- Multiplies the probabilities in effect distribution by a constant.
-- Used for distribution mixing.
function p.effect_mul_p(effect, multiplier)
	local eff = {}
	if multiplier == 0 then
		return eff
	end
	for resource, dist in pairs(effect) do
		eff[resource] = {}
		for delta, prob in pairs(dist) do
			eff[resource][delta] = prob * multiplier
		end
	end
	return eff
end

-- Sums probabilities from effect distributions.
-- Used for distribution mixing.
function p.effect_sum_p(eff1, eff2)
	local eff = {}
	for resource, dist in pairs(eff1) do
		eff[resource] = {}
		for delta, prob in pairs(dist) do
			eff[resource][delta] = prob
		end
	end
	for resource, dist in pairs(eff2) do
		if eff[resource] == nil then
			eff[resource] = {}
		end
		for delta, prob in pairs(dist) do
			if eff[resource][delta] == nil then
				eff[resource][delta] = 0
			end
			eff[resource][delta] = eff[resource][delta] + prob
		end
	end
	for resource, dist in pairs(eff) do
		local total_p = 0
		for _, prob in pairs(dist) do
			total_p = total_p + prob
		end
		if total_p < 0.99 then
			if eff[resource][0] == nil then
				eff[resource][0] = 0
			end
			eff[resource][0] = eff[resource][0] + (1 - total_p)
		end
	end
	return eff
end

-- Expected value of a distribution.
function p.expected_value(dist)
	local delta = 0
	for delta_i, prob_i in pairs(dist) do
		delta = delta + delta_i * prob_i
	end
	return delta
end

-- Replaces each distribution with the expected value in effect.
function p.expected_effect(effect)
	local eff = {}
	for resource, dist in pairs(effect) do
		local delta = p.expected_value(dist)
		if delta ~= 0 then
			eff[resource] = delta
		end
	end
	return eff
end

-- Computes the probability of random value being in the specified range.
function p.range_prob(dist, range)
	local rmin, rmax = util.parse_range(range)
	if rmin == nil or rmax == nil then
		return 0
	end
	local pr = 0
	for delta, prob in pairs(dist) do
		if rmin <= delta and delta <= rmax then
			pr = pr + prob
		end
	end
	return pr
end

-- Computes resource per action for the specified resource and effect.
function p.resource_per_action(eff, resource)
	local a = eff.a
	local r = eff.effect[resource] or 0
	if r == 0 then
		return 0
	end
	-- 1/0 is inf, it is fine
	return r / a
end

return p