-- функция украдена со СтекОверфлова с небольшими изменениями -- htt ps://stackoverflow.com/questions/16026055/lua-printing-specific-key-value-pairs-in-table -- нужна для отладки, в финальном коде не нужна function DeepPrint (e, indent) -- if e is a table, we should iterate over its elements if type(e) == "table" then for k,v in pairs(e) do -- for every element in the table print(indent or "", '[' .. k .. ']', v) if type(v) == "table" then DeepPrint(v, (indent or "") .. "\t") -- recursively repeat the same procedure end end else -- if not, we can just print it print(indent or "", e) end end --[[ diceProb содержит функции для подсчёта вероятности бросков, которые описываются в лиспоподобном формате. Входные данные ожидаются в таком формате: {">=", {"+", "d10", "1"}, "7"}) У значений есть только два типа: список вариантов или константа Константа может выражать вероятность (от 0 до 1) или просто произвольное число Список вариантов — это бросок с описанием возможных исходов и их количества: { {value=2, repeats=1}, {value=3, repeats=2}, ...} Функции типа >=, >, <, <= и т.п. берут список вариантов и возврщают вероятность. Функции типа +, - работаают и с тем, и с тем: для констант они просто складывают константы, а для списков вероятности они добваляют к каждому значению что-то. Операции над константами чуть дешевле. Пример использования: diceProb.evaluate({">", {"+", "2d6", "+3"}, "10"}) -- => 0.41666666666667 (вероятность, что 2d6+3 > 10) Можно передать список значений переменных как второй аргумент: diceProb.evaluate({">", {"+", "2d6", "Прибавка"}, "10"}, {["Прибавка"]="+3"}) -- => 0.41666666666667 (вероятность, что 2d6+Прибавка > 10, где Прибавка=+3) ]] local diceProb = { fn={} } function diceProb.fn.sum(args) local probabilities = {} local constant = 0 for k, v in ipairs(args) do if type(v) == 'table' then table.insert(probabilities, v) else constant = constant + v end end if #probabilities > 2 then local summed_probabilities = probabilities[1] for i=2,#probabilities do summed_probabilities = diceProb.sum_of_rolls(summed_probabilities, probabilities[i]) end probabilities = summed_probabilities end if #probabilities > 0 then local summed = {} for k, v in ipairs(probabilities[1]) do table.insert(summed, {repeats=v.repeats, value=v.value + constant}) end return summed else return constant end end function diceProb.negate(operand) if type(operand) == "table" then local negated = {} for k,v in ipairs(operand) do table.insert(negated, {value=-v.value, repeats=v.repeats}) end return negated else return -operand end end function diceProb.fn.difference(args) if #args == 1 then return diceProb.negate(args[0]) end local sumArgs = {} for k,v in ipairs(args) do if k == 1 then table.insert(sumArgs, v) else table.insert(sumArgs, diceProb.negate(v)) end end return diceProb.fn.sum(sumArgs) end function diceProb.fn.product(args) local probabilities = {} local constant = 1 for k, v in ipairs(args) do if type(v) == 'table' then table.insert(probabilities, v) else constant = constant * v end end if #probabilities > 2 then error('multiplication of dice is not supported (yet?)') end if #probabilities > 0 then local multiplied = {} for k, v in ipairs(probabilities[1]) do table.insert(multiplied, {repeats=v.repeats, value=v.value * constant}) end return multiplied else return constant end end function diceProb.compare_less_than(lower_range, variants, upper_range, include_equal) local total_repeats = 0 local correct_repeats = 0 for k, v in ipairs(variants) do local correct = true if lower_range ~= nil then if v.value < lower_range then correct = false end if v.value == lower_range and not include_equal then correct = false end end if upper_range ~= nil then if v.value > upper_range then correct = false end if v.value == upper_range and not include_equal then correct = false end end total_repeats = total_repeats + v.repeats if correct then correct_repeats = correct_repeats + v.repeats end end return correct_repeats / total_repeats end function diceProb.check_equality(variants, const) local total_repeats = 0 local correct_repeats = 0 for k, v in ipairs(variants) do total_repeats = total_repeats + v.repeats if v.value == const then correct_repeats = correct_repeats + v.repeats end end return correct_repeats / total_repeats end function diceProb.fn.more_or_equals(args) local left = args[1] local right = args[2] if #args ~= 2 then error('≥ operation must have 2 arguments') end if (type(left) == "table") and (type(right) == "table") then -- tbl ≥ tbl error("only one ≥ argument should be a table") elseif type(left) == "table" then -- tbl ≥ const return diceProb.compare_less_than(right, left, nil, true) elseif type(right) == "table" then --const ≥ tbl return diceProb.compare_less_than(nil, right, left, true) else -- const ≥ const if left >= right then return 1 else return 0 end end end function diceProb.fn.more(args) local left = args[1] local right = args[2] if #args ~= 2 then error('> operation must have 2 arguments') end if (type(left) == "table") and (type(right) == "table") then -- tbl ≥ tbl error("only one ≥ argument should be a table") elseif type(left) == "table" then -- tbl ≥ const return diceProb.compare_less_than(right, left, nil, false) elseif type(right) == "table" then --const ≥ tbl return diceProb.compare_less_than(nil, right, left, false) else -- const ≥ const if left > right then return 1 else return 0 end end end function diceProb.fn.less_or_equal(args) local left = args[1] local right = args[2] if #args ~= 2 then error('≤ operation must have 2 arguments') end if (type(left) == "table") and (type(right) == "table") then error("only one ≥ argument should be a table") elseif type(left) == "table" then return diceProb.compare_less_than(nil, left, right, true) elseif type(right) == "table" then return diceProb.compare_less_than(left, right, nil, true) else if left <= right then return 1 else return 0 end end end function diceProb.fn.less(args) local left = args[1] local right = args[2] if #args ~= 2 then error('< operation must have 2 arguments') end if (type(left) == "table") and (type(right) == "table") then error("only one ≥ argument should be a table") elseif type(left) == "table" then return diceProb.compare_less_than(nil, left, right, false) elseif type(right) == "table" then return diceProb.compare_less_than(left, right, false) else if left < right then return 1 else return 0 end end end function diceProb.fn.equal(args) local left = args[1] local right = args[2] if #args ~= 2 then error('= operation must have 2 arguments') end if (type(left) == "table") and (type(right) == "table") then error("only one = argument should be a table") elseif type(left) == "table" then return diceProb.check_equality(left, right) elseif type(right) == "table" then return diceProb.check_equality(right, left) else if left == right then return 1 else return 0 end end end diceProb.functionHandlers = { ['+']=diceProb.fn.sum, ['-']=diceProb.fn.difference, ['*']=diceProb.fn.product, ["≥"]=diceProb.fn.more_or_equals, [">="]=diceProb.fn.more_or_equals, ['>']=diceProb.fn.more, ['<=']=diceProb.fn.less_or_equal, ['≤']=diceProb.fn.less_or_equal, ['<']=diceProb.fn.less, ['=']=diceProb.fn.equal, } diceProb.die_roll_cache = {} -- Список вариантов — это таблица типа -- { {value=2, repeats=1}, {value=3, repeats=2}, ...} -- Где value — значение, repeats — число повторений значения -- Возвращает список вариантов function diceProb.single_die_roll(num_sides) probabilities = {} for i=1, num_sides do table.insert(probabilities, {value=i, repeats=1}) end return probabilities end -- Возвращет список вараиантов суммы двух списков вариантов function diceProb.sum_of_rolls(first_probs, second_probs) local repeats_by_val = {} for _, first in ipairs(first_probs) do for _, second in ipairs(second_probs) do local val = first.value + second.value local repeats = first.repeats * second.repeats repeats_by_val[val] = (repeats_by_val[val] or 0) + repeats end end local values={} for k, v in pairs(repeats_by_val) do table.insert(values, {value=k, repeats=v}) end return values end -- Возвращает список варинатов для XdY function diceProb.complex_die_roll(repeats, num_sides) local basic_roll = diceProb.single_die_roll(num_sides) local result = basic_roll for i = 2,repeats do result = diceProb.sum_of_rolls(result, basic_roll) end return result end -- Читет строку и возвращает либо список вариаантов, либо nil (если это не нотация броска) function diceProb.evaluate_dice_expression(s) if not s:match'%d*[dD]%d' then return nil end local from, to = s:find('[dD]') local repeats, dice = 1, tonumber(s:sub(to+1)) if from > 1 then repeats = tonumber(s:sub(1, from-1) or "1") end local cache_id = repeats .. 'd' .. dice if diceProb.die_roll_cache[cache_id] == nil then diceProb.die_roll_cache[cache_id] = diceProb.complex_die_roll(repeats, dice) end return diceProb.die_roll_cache[cache_id] end function diceProb.evaluate_constant(s) return tonumber(s) end function diceProb.evaluate_form(form, environment) local fn_name = form[1] local computed_args = {} for k, v in ipairs(form) do if k > 1 then table.insert(computed_args, diceProb.evaluate(v, environment)) end end local fn = diceProb.functionHandlers[fn_name] if fn == nil then error('Unknown function: ' .. fn_name) end return fn(computed_args) end function diceProb.evaluate(datum, environment) local t = type(datum) if t == "table" then return diceProb.evaluate_form(datum, environment) elseif t == "string" then local value = (environment and environment[datum]) or diceProb.evaluate_dice_expression(datum) or diceProb.evaluate_constant(datum) if value == nil then error('cannot evaluate datum: ' .. datum .. '[' .. t .. ']') end return value else error('cannot evaluate datum: ' .. datum .. '[' .. t .. ']') end end --[[ diceTable содержит рисование таблиц, оформленных в лиспоподобном формате: { {"столбец", "ID", "тип", "данные1", "данные2", ... }, ... } В качестве типа принимаются значения "список" и "вероятность". Если тип — "список", то дальше идут элементы списка. Если тип — "вероятность", то дальше идёт ровно одна форма, формула расчёта вероятности. Эта формула такая же, как ввод для diceProb.evaluate, причём ID столбцов будут заменяться на элемент списка. Для ID и элемента списка можно задать альтернативное отображение: { {"столбец", {"КостьУмение", "Кость умения"}, "список", {"0", "Нет"}, "d4", "d6", ... }, ... } ]] local diceTable = {} function diceTable.id_or_title(val_with_text, num) if type(val_with_text) == "table" then return val_with_text[num] else return val_with_text end end function diceTable.id(val_with_text) return diceTable.id_or_title(val_with_text, 1) end function diceTable.title(val_with_text) return diceTable.id_or_title(val_with_text, 2) end function diceTable.get_lists(columns) local lists = {} for _, column in ipairs(columns) do if column[3] == "список" then local items = {} for i = 4, #column do table.insert(items, column[i]) end local id = diceTable.id(column[2]) lists[id] = items end end return lists end function diceTable.make_table_rows(columns, a_column_ids, a_current_idx, a_rows) local lists = diceTable.get_lists(columns) local column_ids = a_column_ids if column_ids == nil then column_ids = {} for _, column in ipairs(columns) do if column[3] == "список" then table.insert(column_ids, diceTable.id(column[2])) end end end local current_idx = a_current_idx or 1 if current_idx > #column_ids then return a_rows or {} end local current_id = column_ids[current_idx] local prev_rows = a_rows or {{}} local new_rows = {} local items = lists[current_id] for _,prev_row in ipairs(prev_rows) do for _,item in ipairs(items) do -- TODO rowspan'ы local new_row = {} new_row[current_id] = item for k,v in pairs(prev_row) do new_row[k] = v end table.insert(new_rows, new_row) end end return diceTable.make_table_rows(columns, column_ids, current_idx+1, new_rows) end function diceTable.formatPercent(x) local num = math.floor(x * 10000 + 0.5) / 100 return num .. '%' end function diceTable.get_cell_contents(columns) local rows = diceTable.make_table_rows(columns) local result = {} for _, row_data in pairs(rows) do local cells = {} for idx, column in pairs(columns) do if column[1] ~= "столбец" then error("unknown entity: " .. column[1]) end if column[3] == "список" then cells[idx] = diceTable.title(row_data[diceTable.id(column[2])]) elseif column[3] == "вероятность" then environment = {} for k,v in pairs(row_data) do environment[k] = diceProb.evaluate(diceTable.id(v)) end cells[idx] = diceTable.formatPercent(diceProb.evaluate(column[4], environment)) else error("unknown column type: " .. column[3]) end end table.insert(result, cells) end return result end function diceTable.make_wikitable_contents(columns) local result = '' local rows = diceTable.get_cell_contents(columns) for row_idx, row in ipairs(rows) do local cell_text = "\n|-\n| " for cell_idx, cell in ipairs(row) do cell_text = cell_text .. cell if cell_idx < #row then cell_text = cell_text .. " || " end end result = result .. cell_text end return result end function diceTable.make_wikitable_header(columns) -- TODO: colspan/rowspan local result = '! ' for idx, column in ipairs(columns) do result = result .. diceTable.title(column[2]) if idx < #columns then result = result .. ' !! ' end end return result end function diceTable.make_wikitable(columns) return '{| class="wikitable" style="margin:auto"\n' .. diceTable.make_wikitable_header(columns) .. diceTable.make_wikitable_contents(columns) .. '\n|}' end --[[ Тут нужен парсер S-выражений, но я его пока что не сделал. На входе я хочу что-то лиспообразное, типа такого: ( (столбец Атрибут список d6 d8 d10 d12) (столбец Умение список (0 —) d6 d8 d10 d12) (столбец "Вероятность без переброски" (- 1 (* (< Атрибут 6) (< Умение 6)))) (столбец "Вероятность с переброской" (- 1 (* (< Атрибут 6) (< Умение 6) (< Атрибут 6) (< Умение 6)))) ) Пока что вместо S-выражений просто массивы Lua. ]] print(diceTable.make_wikitable({ {"столбец", "Атрибут", "список", "d6", "d8", "d10", "d12"}, {"столбец", "Умение", "список", {"0", "—"}, "d6", "d8", "d10", "d12"}, {"столбец", "Вероятность без переброски", "вероятность", {"-", "1", {"*", {"<", "Атрибут", "6"}, {"<", "Умение", "6"}}}}, {"столбец", "Вероятность с переброской", "вероятность", {"-", "1", {"*", {"<", "Атрибут", "6"}, {"<", "Умение", "6"}, {"<", "Атрибут", "6"}, {"<", "Умение", "6"}}}} }))
Write, Run & Share Lua code online using OneCompiler's Lua online compiler for free. It's one of the robust, feature-rich online compilers for Lua language, running the latest Lua version 5.4. Getting started with the OneCompiler's Lua editor is easy and fast. The editor shows sample boilerplate code when you choose language as Lua and start coding.
OneCompiler's Lua online editor supports stdin and users can give inputs to programs using the STDIN textbox under the I/O tab. Following is a sample Lua program which takes name as input and prints hello message with your name.
name = io.read("*a")
print ("Hello ", name)
Lua is a light weight embeddable scripting language which is built on top of C. It is used in almost all kind of applications like games, web applications, mobile applications, image processing etc. It's a very powerful, fast, easy to learn, open-source scripting language.
-- global variables
a = 10
-- local variables
local x = 30
Value Type | Description |
---|---|
number | Represents numbers |
string | Represents text |
nil | Differentiates values whether it has data or not |
boolean | Value can be either true or false |
function | Represents a sub-routine |
userdata | Represents arbitary C data |
thread | Represents independent threads of execution. |
table | Can hold any value except nil |
While is also used to iterate a set of statements based on a condition. Usually while is preferred when number of iterations are not known in advance.
while(condition)
do
--code
end
Repeat-Until is also used to iterate a set of statements based on a condition. It is very similar to Do-While, it is mostly used when you need to execute the statements atleast once.
repeat
--code
until( condition )
For loop is used to iterate a set of statements based on a condition.
for init,max/min value, increment
do
--code
end
Function is a sub-routine which contains set of statements. Usually functions are written when multiple calls are required to same set of statements which increase re-usuability and modularity.
optional_function_scope function function_name( argument1, argument2, argument3........, argumentn)
--code
return params with comma seperated
end