Module:Build bracket/StateChecks
Appearance
local StateChecks = {}
-- Bound at runtime
local state, config, Helpers
-- Local aliases (filled in bind)
local isempty, notempty
function StateChecks.bind(_state, _config, _Helpers)
state, config, Helpers = _state, _config, _Helpers
isempty = Helpers.isempty
notempty = Helpers.notempty
end
-- reads entries
function StateChecks.isBlankEntry(col, row)
local colEntries = state.entries[col]
if not colEntries then return true end
local e = colEntries[row]
if not e then return true end
return isempty(e.team) and isempty(e.text)
end
-- reads entries, teamsPerMatch, forceseeds
function StateChecks.showSeeds(j, i)
local row = state.entries[j]
if not row then return false end
local e = row[i]
if not e or e.ctype ~= 'team' then return false end
-- Force show, or if this team already has a seed
if config.forceseeds or notempty(e.seed) then
return true
end
local group = e.group
local tpm = state.teamsPerMatch[j] or 2
local step = 2 -- layout uses every 2 rows for teams in a match
local function neighborHasSeed(idx)
local n = row[idx]
return n and n.ctype == 'team' and n.group == group and notempty(n.seed)
end
for k = 1, tpm - 1 do
local plus = i + step * k
local minus = i - step * k
if plus <= config.r and neighborHasSeed(plus) then return true end
if minus >= 1 and neighborHasSeed(minus) then return true end
end
return false
end
-- mutates state.hide
function StateChecks.isRoundHidden(j, i, headerindex)
local col = state.entries[j]
if not col then return end
local e = col[i]
if not e then return end
local hidx = headerindex or e.headerindex
if not state.hide[j] then state.hide[j] = {} end
-- If there is a parent header, this header should be shown
if notempty(e.pheader) then
state.hide[j][hidx] = false
return
end
-- Scan forward until next header (or end of round).
local row = i + 1
while row <= config.r do
local r = col[row]
if r and r.ctype == 'header' then
break
end
if not StateChecks.isBlankEntry(j, row) then
state.hide[j][hidx] = false
break
end
row = row + 1
end
end
-- reads entries, rlegs, autolegs
function StateChecks.teamLegs(j, i)
local col = state.entries[j]
if not col then return state.rlegs[j] or 1 end
local e = col[i]
if not e or e.ctype ~= 'team' then
return state.rlegs[j] or 1
end
-- start with round default
local legs = state.rlegs[j] or 1
-- named override (if present)
if notempty(e.legs) then
legs = tonumber(e.legs) or legs
end
-- helper: treat nil/'' and values containing 'nbsp' as blank
local function isScoreBlank(v)
if isempty(v) then return true end
return type(v) == 'string' and v:find('nbsp', 1, true) ~= nil
end
-- autolegs: count contiguous non-blank leg entries starting at 1
if config.autolegs and e.score then
local l = 1
while not isScoreBlank(e.score[l]) do
l = l + 1
end
local inferred = l - 1
if inferred > 0 then
legs = inferred
end
end
return legs
end
-- used for bye detection
function StateChecks.roundIsEmpty(j, i)
local col = state.entries[j]
if not col then return true end
local row = i + 1
while row <= config.r do
local e = col[row]
if e and e.ctype == 'header' then
break
end
if not StateChecks.isBlankEntry(j, row) then
return false
end
row = row + 1
end
return true
end
-- default header text when none provided
function StateChecks.defaultHeaderText(j, headerindex)
if headerindex ~= 1 then
return 'Lower round ' .. tostring(j)
end
local c = tonumber(config.c) or j
local rem = c - j
if rem == 0 then
return 'Final'
elseif rem == 1 then
return 'Semifinals'
elseif rem == 2 then
return 'Quarterfinals'
else
return 'Round ' .. tostring(j)
end
end
function StateChecks.noPaths(j, i)
-- how many path columns to check
local cols = state.hascross[j] and 3 or 2
-- path cells: any nonzero entry in [k][1][n] means there's a path
local pcj = state.pathCell[j]
local pci = pcj and pcj[i]
if pci then
for k = 1, cols do
local ktab = pci[k]
local dir1 = ktab and ktab[1]
if dir1 then
for n = 1, 4 do
local v = dir1[n]
if v and v ~= 0 then
return false
end
end
end
end
end
-- cross cells: left/right flag of 1 means there's a cross path
if state.hascross[j] then
local ccj = state.crossCell[j]
local cci = ccj and ccj[i]
if cci then
local left, right = cci.left, cci.right
if (left and left[1] == 1) or (right and right[1] == 1) then
return false
end
end
end
return true
end
return StateChecks