Module:SCurve
From Fallen London Wiki (Staging)
Documentation for this module may be created at Module:SCurve/doc
local p = {}
local function get_arg_or_nil(args, name)
local arg = args[name]
if arg == '' then
return nil
end
return arg
end
local function get_arg(args, parent_args, name, default)
return get_arg_or_nil(args, name) or get_arg_or_nil(parent_args, name) or default
end
--[[
Round a number.
Input parameters:
@num: the number to round
@power: the number of decimal digits to round to
If power is non-zero, this is the same as {{#expr: num round power}}.
If power is zero, this uses round-half-to-even, as is typically used in-game.
]]
local function round(num, power)
if num == 0 then
return 0
end
if power ~= 0 then
return mw.ext.ParserFunctions.expr(tostring(num) .. 'round' .. tostring(power))
end
local anum = math.abs(num)
local sign = math.floor(num / anum)
local frac = math.fmod(anum, 1)
if (frac == 0.5 and math.ceil(anum) % 2 == 0) or frac > .5 then
return sign * math.ceil(anum)
end
if math.floor(anum) == 0 then
-- silly, but needed to work around -0
return 0
end
return sign * math.floor(anum)
end
local function make_scurve(height, k, midpoint, y_offset)
return function(x, round_power)
return round(y_offset + height / (1 + math.exp(-k * (x - midpoint))), round_power)
end
end
function p.eval_scurve(frame)
local args = frame.args
local parent_args = frame:getParent().args
local height = tonumber(get_arg(args, parent_args, 'height', 1))
local k = tonumber(get_arg(args, parent_args, 'k', 1))
local midpoint = tonumber(get_arg(args, parent_args, 'midpoint', 0))
local y_offset = tonumber(get_arg(args, parent_args, 'y_offset', 0))
local x = tonumber(get_arg(args, parent_args, 'x', nil))
local round_power = 3
if get_arg(args, parent_args, 'Round', nil) == 'yes' then
round_power = 0
end
return make_scurve(height, k, midpoint, y_offset)(x, round_power)
end
local function add_column(table_rows, table_data)
table_rows[1]:tag('th')
:wikitext(table_data[1])
for row = 2, #(table_rows) do
table_rows[row]:tag('td')
:wikitext(table_data[row])
end
end
function p.scurve_table(frame)
local args = frame.args
local parent_args = frame:getParent().args
local height = tonumber(get_arg(args, parent_args, 'height', 1))
local k = tonumber(get_arg(args, parent_args, 'k', 1))
local midpoint = tonumber(get_arg(args, parent_args, 'midpoint', 0))
local y_offset = tonumber(get_arg(args, parent_args, 'y_offset', 0))
local xleft = tonumber(get_arg(args, parent_args, 'xleft', nil) or
get_arg(args, parent_args, 'xmin', 0))
local xright = tonumber(get_arg(args, parent_args, 'xright', nil) or
get_arg(args, parent_args, 'xmax', xleft))
local low_cap = get_arg(args, parent_args, 'lowcap', 'no') == 'yes'
local high_cap = get_arg(args, parent_args, 'highcap', 'no') == 'yes'
local compact = get_arg(args, parent_args, 'compact', 'no') == 'yes'
local condition = args.condition
local show_ending_condition = get_arg(args, parent_args, 'show_ending_condition', 'no') == 'yes'
local condition_increase = tonumber(get_arg(args, parent_args, 'condition_increase', 1))
local effect = get_arg(args, parent_args, 'Effect', nil)
local max_columns = tonumber(get_arg(args, parent_args, 'max_columns', nil))
local round_power = 3
if get_arg(args, parent_args, 'Round', 'no') == 'yes' then
round_power = 0
end
local tbl = mw.html.create('table')
:addClass('article-table')
local function make_rows(tbl, table_rows, show_ending_condition)
table.insert( table_rows, tbl:tag('tr') )
table.insert( table_rows, tbl:tag('tr') )
if show_ending_condition then
table.insert( table_rows, tbl:tag('tr') )
add_column(table_rows, { 'Starting ' .. condition, effect, 'Ending ' .. condition } )
else
add_column(table_rows, { condition, effect } )
end
return table_rows
end
local table_rows = make_rows(tbl, {}, show_ending_condition)
local scurve = make_scurve(height, k, midpoint, y_offset)
local function make_compact_condition_data(start, last, val)
local key
if start == last then
key = tostring(start)
else
key = start .. '–' .. last
end
if not low_cap and
((k > 0 and val == y_offset) or
(k < 0 and val == y_offset + height)) then
key = '≤' .. key
elseif not high_cap and
((k < 0 and val == y_offset) or
(k > 0 and val == y_offset + height)) then
key = '≥' .. key
end
return key
end
local start = nil
local last = nil
local val = nil
local num_columns = 0
local overflow = false
local step = math.floor((xright - xleft) / math.abs(xright - xleft))
for x=xleft,xright,step do
local result = scurve(x, round_power)
if compact then
if val ~= nil and result ~= val then
local heading = make_compact_condition_data(start, last, val)
local table_data = { heading, val }
if show_ending_condition then
local ending_condition = make_compact_condition_data(start + condition_increase, last + condition_increase, val)
table.insert( table_data, ending_condition )
end
add_column(table_rows, table_data)
num_columns = num_columns + 1
start = nil
end
if x == xright then
local heading = make_compact_condition_data(start or x, x, result)
local table_data = { heading, result }
if show_ending_condition then
local ending_condition = make_compact_condition_data((start or x) + condition_increase, x + condition_increase, result)
table.insert( table_data, ending_condition )
end
add_column(table_rows, table_data)
num_columns = num_columns + 1
else
last = x
if start == nil then
if max_columns ~= nil and num_columns >= max_columns then
table_rows = make_rows(tbl, {}, show_ending_condition)
num_columns = 0
overflow = true
end
start = x
val = result
end
end
else
if max_columns ~= nil and num_columns >= max_columns then
table_rows = make_rows(tbl, {}, show_ending_condition)
num_columns = 0
overflow = true
end
local table_data = { x, result }
if show_ending_condition then
local ending_condition = x + condition_increase
table.insert( table_data, ending_condition )
end
add_column(table_rows, table_data)
num_columns = num_columns + 1
end
end
if overflow and num_columns < max_columns then
table_rows[1]:tag('th')
:attr('colspan', max_columns - num_columns)
for row = 2, #(table_rows) do
table_rows[row]:tag('td')
:attr('colspan', max_columns - num_columns)
end
end
return tostring(tbl)
end
return p