Module:Build bracket/Logic
Appearance
local Logic = {}
-- ================
-- updateMaxLegs
-- ================
function Logic.updateMaxLegs(state, config, Helpers)
state.maxlegs = state.maxlegs or {}
for j = config.minc, config.c do
state.maxlegs[j] = state.rlegs[j]
for i = 1, config.r do
local e = state.entries[j] and state.entries[j][i]
if e then
if Helpers.notempty(e.legs) then
state.maxlegs[j] = math.max(state.rlegs[j], e.legs)
end
if config.autolegs and e.score then
local l = 1
repeat l = l + 1
until Helpers.isempty(e.score) or Helpers.isempty(e.score[l])
state.maxlegs[j] = math.max(state.maxlegs[j], l - 1)
end
end
end
end
end
-- ================
-- matchGroups
-- ================
function Logic.matchGroups(state, config)
state.matchgroup = state.matchgroup or {}
for j = config.minc, config.c do
state.matchgroup[j] = {}
local mgj = state.matchgroup[j]
local tpm = tonumber(state.teamsPerMatch and state.teamsPerMatch[j]) or 2
if tpm < 1 then tpm = 2 end
local col = state.entries[j]
if col then
for i = 1, config.r do
local e = col[i]
if e and e.ctype == 'team' then
local idx = tonumber(e.index) or tonumber(e.altindex) or i
local g = math.ceil(idx / tpm)
mgj[i] = g
e.group = g
end
end
end
end
end
-- =================
-- computeAggregate
-- =================
function Logic.computeAggregate(state, config, Helpers, StateChecks)
if config.aggregate_mode == 'off' or config.aggregate_mode == 'manual' then return end
local modeLow = (config.boldwinner_mode == 'low')
local function numlead(s)
if not s or s == '' then return nil end
return tonumber((s):match('^%d+'))
end
local function buildGroupsForRound(j)
local groups = {}
local mg = state.matchgroup[j] or {}
for i = 1, config.r do
local e = state.entries[j] and state.entries[j][i]
if e and e.ctype == 'team' then
local gid = mg[i]
if gid ~= nil then
groups[gid] = groups[gid] or {}
table.insert(groups[gid], i)
end
end
end
return groups
end
local function preparseLegs(j)
local legNums = {}
for i = 1, config.r do
local e = state.entries[j] and state.entries[j][i]
if e and e.ctype == 'team' then
local L = StateChecks.teamLegs(state, config, j, i)
if config.aggregate and L > 1 and e.score and e.score.agg ~= nil then
legNums[i] = {}
for l = 1, L do
legNums[i][l] = numlead(e.score[l])
end
end
end
end
return legNums
end
for j = config.minc, config.c do
local groups = buildGroupsForRound(j)
local legNums = preparseLegs(j)
if config.aggregate_mode == 'score' then
for _, members in pairs(groups) do
for _, i in ipairs(members) do
local e = state.entries[j][i]
if e and e.ctype == 'team' and config.aggregate and StateChecks.teamLegs(state, config, j, i) > 1 then
if Helpers.isempty(e.score.agg) then
local sum, nums = 0, legNums[i]
if nums then
for _, v in ipairs(nums) do if v then sum = sum + v end end
e.score.agg = tostring(sum)
end
end
end
end
end
else
-- 'sets'/'legs': count leg wins (ties give no win)
for _, members in pairs(groups) do
local wins = {}
local commonLegs = math.huge
for _, i in ipairs(members) do
local nums = legNums[i]
local L = (nums and #nums) or 0
if L == 0 then commonLegs = 0; break end
if L < commonLegs then commonLegs = L end
end
for l = 1, commonLegs do
local allNumeric = true
for _, i in ipairs(members) do
if not (legNums[i] and legNums[i][l] ~= nil) then
allNumeric = false; break
end
end
if allNumeric then
local best, bestIndex, tie = nil, nil, false
for _, i in ipairs(members) do
local v = legNums[i][l]
if best == nil then
best, bestIndex, tie = v, i, false
else
if (modeLow and v < best) or (not modeLow and v > best) then
best, bestIndex, tie = v, i, false
elseif v == best then
tie = true
end
end
end
if not tie and bestIndex then
wins[bestIndex] = (wins[bestIndex] or 0) + 1
end
end
end
for _, i in ipairs(members) do
local e = state.entries[j][i]
if e and e.ctype == 'team' and config.aggregate and StateChecks.teamLegs(state, config, j, i) > 1 then
if Helpers.isempty(e.score.agg) then
e.score.agg = tostring(wins[i] or 0)
end
end
end
end
end
end
end
-- ==========
-- boldWinner
-- ==========
function Logic.boldWinner(state, config, Helpers, StateChecks)
local modeLow = (config.boldwinner_mode == 'low')
local aggOnly = config.boldwinner_aggonly
local function isWin(mine, theirs)
if modeLow then return mine < theirs else return mine > theirs end
end
local function isAggWin(mine, theirs, l)
if l == 'agg' and config.aggregate_mode == 'sets' then
return mine > theirs
else
return isWin(mine, theirs)
end
end
local function boldScore(j, i, l)
local e = state.entries[j][i]
if not e or e.ctype ~= 'team' then return 'normal' end
local raw = e.score[l] or ''
local mine = tonumber((raw):match('^%d+'))
if not mine then return 'normal' end
local comps = {}
for oppIndex, groupId in pairs(state.matchgroup[j]) do
if groupId == state.matchgroup[j][i] and oppIndex ~= i then
local theirraw = state.entries[j][oppIndex].score[l] or ''
local theirs = tonumber((theirraw):match('^%d+'))
if not theirs then return 'normal' end
table.insert(comps, theirs)
end
end
for _, v in ipairs(comps) do
if not isAggWin(mine, v, l) then return 'normal' end
end
if l ~= 'agg' then
e.wins = (e.wins or 0) + 1
else
e.aggwins = 1
end
return 'bold'
end
local function boldTeam(j, i, useAggregate)
local e = state.entries[j][i]
local winsKey = useAggregate and 'aggwins' or 'wins'
local legs = StateChecks.teamLegs(state, config, j, i)
if not useAggregate then
if (e[winsKey] or 0) > legs / 2 then return 'bold' end
local checkFn = config.autolegs and Helpers.notempty or function(val) return not Helpers.isempty(val) end
for l = 1, legs do
local sv = e.score[l]
if not checkFn(sv) or (type(sv) == 'string' and sv:find('nbsp', 1, true)) then
return 'normal'
end
end
end
for oppIndex, groupId in pairs(state.matchgroup[j]) do
if groupId == state.matchgroup[j][i] and oppIndex ~= i then
if (e[winsKey] or 0) <= tonumber(state.entries[j][oppIndex][winsKey] or 0) then
return 'normal'
end
end
end
return 'bold'
end
for j = config.minc, config.c do
for i = 1, config.r do
local e = state.entries[j] and state.entries[j][i]
if e and e.ctype == 'team' then
e.wins, e.aggwins = 0, 0
end
end
for i = 1, config.r do
local e = state.entries[j] and state.entries[j][i]
if e and e.ctype == 'team' then
local legs = StateChecks.teamLegs(state, config, j, i)
if not aggOnly then
for l = 1, legs do
e.score.weight[l] = boldScore(j, i, l)
end
end
if config.aggregate and legs > 1 then
e.score.weight.agg = boldScore(j, i, 'agg')
end
end
end
if not aggOnly then
for i = 1, config.r do
local e = state.entries[j] and state.entries[j][i]
if e and e.ctype == 'team' then
local useAggregate = config.aggregate and StateChecks.teamLegs(state, config, j, i) > 1
e.weight = boldTeam(j, i, useAggregate)
end
end
end
end
end
return Logic