local fn = {}
fn.shuffle = function(list)
for i = #list, 2, -1 do
local j = math.random(i)
list[i], list[j] = list[j], list[i]
end
return list
end
fn.scramble = function(list)
return fn.shuffle(table.copy(list))
end
fn.urnd = function(min,max)
local r = {}
for i=min,max do r[1 + (i - min)] = i end
fn.shuffle(r)
return r
end
fn.uniq = function(lst)
local hash = {}
local new = {}
for i,v in ipairs(lst) do
if not hash[v] then
hash[v] = true
new[#new+1] = v
end
end
return new
end
fn.copy = function(t)
local new = {}
for i,v in pairs(t) do new[i] = v end
setmetatable(new,getmetatable(t))
return new
end
fn.deepcopy = table.copy or function(t)
new = {}
for k,v in pairs(t) do
if type(v) == 'table' then
new[k] = fn.deepcopy(v)
else
new[k] = v
end
end
return new
end
fn.append = function(r1, r2)
local new = fn.copy(r1)
for i=1,#r2 do
new[#new + 1] = r2[i]
end
return new
end
fn.merge = function(base,override)
local new = fn.copy(base)
for k,v in pairs(override) do
new[k] = v
end
return new
end
fn.deepmerge = function(base,override,func)
local new = {}
local keys = fn.append(fn.keys(base),fn.keys(override))
for _,k in pairs(keys) do
if type(base[k]) == 'table' and
type(override[k]) == 'table' then
new[k] = fn.deepmerge(base[k], override[k], func)
elseif func and override[k] and base[k] then
new[k] = func(base[k],override[k], k)
elseif override[k] then
new[k] = override[k]
else
new[k] = base[k]
end
end
return new
end
fn.has = function(tbl,value,eqfn)
for k,v in pairs(tbl) do
if eqfn then
if eqfn(v,value,tbl) then return true, k end
else
if value == v then return true, k end
end
end
return false, nil
end
fn.keys = function(lst)
local ks = {}
for k,_ in pairs(lst) do
ks[#ks + 1] = k
end
return ks
end
fn.pick = function(lst)
local keys = fn.keys(lst)
local k = keys[math.random(#keys)]
return k, lst[k]
end
fn.unpack = function(tbl,i)
i = i or 1
if #tbl == i then return tbl[i] end
return tbl[i], fn.unpack(tbl, i+1)
end
fn.split = function(...) return fn.unpack(sorcery.lib.str.explode(...)) end
fn.each = function(tbl,f)
local r = {}
for k,v in pairs(tbl) do
local v, c = f(v,k)
r[#r+1] = v
if c == false then break end
end
return r
end
fn.each_o = function(tbl,f)
local keys = fn.keys(tbl)
table.sort(keys)
return fn.each(keys, function(k,i)
return f(tbl[k],k,i)
end)
end
fn.iter = function(tbl,fn)
for i,v in ipairs(tbl) do fn(v, i) end
end
fn.map = function(tbl,fn)
local new = {}
for k,v in pairs(tbl) do
local nv, nk = fn(v, k)
new[nk or k] = nv
end
return new
end
fn.fold = function(tbl,fn,acc)
if #tbl == 0 then
fn.each_o(tbl, function(v)
acc = fn(acc, v, k)
end)
else
for i,v in ipairs(tbl) do
acc = fn(acc,v,i)
end
end
return acc
end
fn.walk = function(tbl,path)
if type(path) == 'table' then
for _,p in pairs(path) do
if tbl == nil or tbl[p] == nil then return nil end
tbl = tbl[p]
end
else
tbl = tbl[path]
end
return tbl
end
fn.proto = function(tbl,proto)
local meta = getmetatable(tbl)
local nm = {__index = proto or tbl}
if meta ~= nil then
nm = table.copy(meta)
nm.__index = proto
nm.__metatable = meta
end
return setmetatable(tbl or {},nm)
end
fn.defaults = function(dft, tbl)
tbl = tbl or {}
local rp = {}
for k,v in pairs(dft) do
if tbl[k] == nil then rp[k] = v end
end
return fn.proto(rp, tbl)
end
fn.case = function(e, c)
if type(c[e]) == 'function'
then return (c[e])(e)
else return c[e]
end
end
fn.cond = function(exp, c)
for i, v in ipairs(c) do
if c[1](exp) then return c[2](exp) end
end
end
fn.strmatch = function(tbl, str)
if tbl == str then return true end
if type(tbl) == 'string' then return false end
return fn.has(tbl, str)
end
fn.select = function(tbl, prop, ...)
local keycache
local check if type(prop) == 'function' then
check = prop
keycache = ...
else
local val val, keycache = ...
check = function(ent) return ent[prop] == val end
end
for k,v in pairs(tbl) do
if (not keycache) or (not keycache[k]) then -- help avoid expensive selectors
if check(v,k) then
if keycache then keycache[k] = true end
return v, k
end
end
end
end
return fn