Module:Build bracket/StateChecks

local StateChecks = {}

-- =========================
-- 1) MODULE BINDINGS
-- =========================
-- Bound at runtime
local state, config, Helpers

-- Local aliases (filled in bind; with fallbacks)
local isempty, notempty

function StateChecks.bind(_state, _config, _Helpers)
    state, config, Helpers = _state, _config, _Helpers
    isempty  = (Helpers and Helpers.isempty)  or function(v) return v == nil or v == "" end
    notempty = (Helpers and Helpers.notempty) or function(v) return v ~= nil and v ~= "" end
end

-- =========================
-- 2) CONTENT CHECKS
-- =========================
-- True when the entry at (col,row) is empty for rendering purposes.
-- For 'team' → check team text; for 'text' → check text; everything else counts as blank.
function StateChecks.isBlankEntry(col, row)
    local colEntries = state.entries and state.entries[col]
    if not colEntries then return true end

    local e = colEntries[row]
    if not e then return true end

    local ct = e.ctype
    if ct == "team" then
        return isempty(e.team)
    elseif ct == "text" then
        return isempty(e.text)
    end
    -- headers/lines/blanks or anything else are non-content here
    return true
end

-- =========================
-- 3) SEED VISIBILITY
-- =========================
-- Show seeds when forced, when this team has a seed, or when any teammate in the same match has a seed.
function StateChecks.showSeeds(j, i)
    local col = state.entries and state.entries[j]
    if not col then return false end

    local e = col[i]
    if not e or e.ctype ~= "team" then return false end

    if config.forceseeds or notempty(e.seed) then
        return true
    end

    local group = e.group
    local tpm   = state.teamsPerMatch[j] or 2
    if tpm <= 1 then return false end

    -- Teams are laid out every 2 rows per match.
    local step  = 2
    local R     = config.r

    local function neighborHasSeed(idx)
        local n = col[idx]
        return n and n.ctype == "team" and n.group == group and notempty(n.seed)
    end

    -- Check teammates forward/back within the match block
    for k = 1, tpm - 1 do
        local plus  = i + step * k
        local minus = i - step * k
        if plus  <= R and neighborHasSeed(plus)  then return true end
        if minus >= 1 and neighborHasSeed(minus) then return true end
    end

    return false
end

-- =========================
-- 4) ROUND VISIBILITY (HIDE)
-- =========================
-- Mutates state.hide[j][hidx] to false when content is found under a header (keeps legacy semantics).

function StateChecks.teamLegs(j, i)
    local col          = state.entries and state.entries[j]
    local roundDefault = (state.rlegs and state.rlegs[j]) or 1
    if not col then return roundDefault end

    local e = col[i]
    if not e or e.ctype ~= "team" then return roundDefault end

    local legs = roundDefault
    if notempty(e.legs) then
        legs = tonumber(e.legs) or legs
    end

    -- Treat nil/'' and strings 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

    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

-- =========================
-- 6) ROUND CONTENT CHECK
-- =========================
-- Used for 'byes' detection: true when there is no content until the next header (or end).
function StateChecks.roundIsEmpty(j, i)
    local col = state.entries and state.entries[j]
    if not col then return true end

    local row, R = i + 1, config.r
    while row <= 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

-- =========================
-- 7) DEFAULT HEADER TEXT
-- =========================
-- Default header text when none provided (keeps legacy strings).
function StateChecks.defaultHeaderText(j, headerindex)
    if headerindex ~= 1 then
        return "Lower round " .. tostring(j)
    end

    local base    = config.base or 0
    local orig_j  = j + base
    local total   = config.c_total or (config.c + base)
    local rem     = total - orig_j

    if rem == 0 then
        return "Final"
    elseif rem == 1 then
        return "Semifinals"
    elseif rem == 2 then
        return "Quarterfinals"
    else
        return "Round " .. tostring(orig_j)
    end
end

-- =========================
-- 8) PATH PRESENCE CHECK
-- =========================
-- True when the path block between j → j+1 at row i has no visible lines at all.
function StateChecks.noPaths(j, i)
    local hasCross = state.hascross and state.hascross[j]
    local cols     = hasCross and 3 or 2

    -- Path cells: any nonzero border means a path
    local pcj = state.pathCell and state.pathCell[j]
    local pci = pcj and pcj[i]
    if pci then
        for k = 1, cols do
            local edges = pci[k] and pci[k][1]
            if edges and (
                (edges[1] and edges[1] ~= 0) or
                (edges[2] and edges[2] ~= 0) or
                (edges[3] and edges[3] ~= 0) or
                (edges[4] and edges[4] ~= 0)
            ) then
                return false
            end
        end
    end

    -- Cross cells: left/right flag at index 1 means a cross path
    if hasCross then
        local ccj = state.crossCell and 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

Content Disclaimer

Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.

  1. The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
  2. There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
  3. It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
  4. Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
  5. Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.