Module:Team bracket
Jump to navigation
Jump to search
Script error: No such module "High-use". Template:Module rating
This module implements a generic visual representation of the bracket of a single-elimination tournament with any number of rounds. For common usage, use the {{64TeamBracket}}, {{32TeamBracket}}, {{16TeamBracket}}, {{8TeamBracket}}, {{4TeamBracket}}, {{2TeamBracket}} templates.
Usage
{{#invoke: Team bracket | main | rounds = | RD1-group1 = | RD1 = | RD1-seed1 = | RD1-team1 = | RD1-score1 = ... }}
Parameters
Parameter | Description |
---|---|
rounds |
number of rounds. Use 1 for a 2 team bracket, 2 for a 4 team bracket, 3 for an 8 team bracket, ...
|
maxround |
maximum round to display. This parameter should be omitted unless it is less than the default value set by rounds .
|
seed-width |
the width of the cells for seeds. Plain numbers are assumed to be in px units (e.g., 25 or 25px 2em for 2em or auto for automatic width sizing)
|
team-width |
the width of the cells for team names. Plain numbers are assumed to be in px units (e.g., 200 for 200px or 15em for 15em or auto for automatic width sizing)
|
score-width |
the width of the cells for scores. Plain numbers are assumed to be in px units (e.g., 25 or 25px 2em for 2em or auto for automatic width sizing)
|
compact |
set to yes for compact bracket and to disable groups.
|
seeds |
set to no to omit seed cells, and yes to always show seed cells
|
sets or legs |
the number of sets/legs in each round of matches (delimit with / for different numbers of sets or legs per round) |
nowrap |
set to yes to prevent lines from wrapping
|
byes |
set to 1 , 2 , ... to specify the maximum round number with byes
|
boldwinner |
set to high to automatically bold the seed/team/scores for the team with the highest score, and low for the lowest score
|
hideomittedscores |
set to 1 to hide all omitted score cells. To only omit score cells from the second set or leg onwards, use 2
|
sepwidth |
set to 1 or 2 to override the default separator width
|
headings |
set to no to omit the column headings
|
RDn |
The name of round n. Defaults are "Round of m", ..., "Quarterfinals", "Semifinals", and "Finals", where m is the number of teams in the round. |
RDn-groupm |
The name of group m in round n. For each round, every set of four teams is classified as a group. |
RDn-seedm |
The seed of team m in round n. For round 1, this value defaults to the conventional seed allocation for tournaments. If omitted, the cell is hidden. To hide seeds for round 1, the value must be explicitly set to be empty. m is the zero-padded position. |
RDn-teamm |
The name of team m in round n. |
RDn-scorem |
The score of team m in round n. |
RDn-scorem-s |
The score of team m in round n and set s (or leg for multileg matches). Alternatively, the last score in the round can be specified using the -agg suffix.
|
RD1-omit |
Selectively omit teams from the first round. For example, use 1 / 2 / 5 / 6 to omit team1, team2, team5, and team6 from the first round.
|
RD-shade |
Background color for the RDn headings
|
RDn-shadem-s |
Background coloring for team m in round n and set s (or leg for multileg matches). |
RDn-RDn+1-path |
Set to 0 to omit the path between round n and round n+1.
|
float |
Float the bracket to the left or right or center or centre of the page.
|
clear |
Set to no to prevent "clearing" the left/right side of the page before floating to the left/right. This parameter is only valid with |float=left or |float=right .
|
aggregate |
Set to sets or legs to sum the sets/legs won and append to the end of the scores. Set to score to sum the scores from each set/leg and append to the end of the scores. Set to y or yes to enable the -agg suffix, but without any auto computation. Only works when there are two or more legs/sets in the round. Any automatically computed value can be overridden by setting the value manually with the -agg suffix for the score.
|
Examples
No seeds
{{#invoke: Team bracket | main | rounds = 2 | seeds = no }}
Semifinals | Finals | ||||||
Compact
{{#invoke: Team bracket | main | rounds = 2 | compact = yes }}
Semifinals | Finals | ||||||||
Third place
{{#invoke: Team bracket | main | rounds = 2 | seeds = no | RD2b = Third place }}
Semifinals | Finals | ||||||
Third place | |||||||
Groups
{{#invoke: Team bracket | main | autoseeds = y | rounds = 3 | RD1-group1 = Pacific | RD1-group2 = Mountain | RD2-group1 = West }}
Quarterfinals | Semifinals | Finals | ||||||||||||
1 | ||||||||||||||
8 | ||||||||||||||
Pacific | ||||||||||||||
5 | ||||||||||||||
4 | ||||||||||||||
West | ||||||||||||||
3 | ||||||||||||||
6 | ||||||||||||||
Mountain | ||||||||||||||
7 | ||||||||||||||
2 |
Sets
{{#invoke: Team bracket | main | autoseeds = y | rounds = 3 | sets = 3 / 5 / 5 }}
Quarterfinals | Semifinals | Finals | ||||||||||||||||||||||
1 | ||||||||||||||||||||||||
8 | ||||||||||||||||||||||||
5 | ||||||||||||||||||||||||
4 | ||||||||||||||||||||||||
3 | ||||||||||||||||||||||||
6 | ||||||||||||||||||||||||
7 | ||||||||||||||||||||||||
2 |
Aggregate
{{#invoke: Team bracket | main | autoseeds = y | rounds = 3 | legs = 2 | aggregate = y }}
Quarterfinals | Semifinals | Finals | ||||||||||||||||||
1 | ||||||||||||||||||||
8 | ||||||||||||||||||||
5 | ||||||||||||||||||||
4 | ||||||||||||||||||||
3 | ||||||||||||||||||||
6 | ||||||||||||||||||||
7 | ||||||||||||||||||||
2 |
Bold winner with byes and hide omitted scores
{{#invoke: Team bracket | main |rounds=3|byes=1|legs=3/5/5|sepwidth=1|boldwinner=high|hideomittedscores = 1 |RD1-seed3=4|RD1-team3=[[BC Vienna|Hallmann Vienna]]|RD1-score3-1=80|RD1-score3-2=66|RD1-score3-3=64 |RD1-seed4=5|RD1-team4=[[WBC Wels|WBC Raiffeisen Wels]]|RD1-score4-1=64|RD1-score4-2=81|RD1-score4-3=69 |RD1-seed7=3|RD1-team7=[[Kapfenberg Bulls|ece Bulls Kapfenberg]]|RD1-score7-1=97|RD1-score7-2=95 |RD1-seed8=6|RD1-team8=[[Arkadia Traiskirchen Lions]]|RD1-score8-1=80|RD1-score8-2=82 <!--SF--> |RD2-seed1=1|RD2-team1=[[Oberwart Gunners|Redwell Gunners Oberwart]]|RD2-score1-1=75|RD2-score1-2=89|RD2-score1-3=57|RD2-score1-4=79|RD2-score1-5=77 |RD2-seed2=5|RD2-team2=[[WBC Wels|WBC Raiffeisen Wels]]|RD2-score2-1=84|RD2-score2-2=83|RD2-score2-3=63|RD2-score2-4=62|RD2-score2-5=67 |RD2-seed3=2|RD2-team3=[[Swans Gmunden]]|RD2-score3-1=73|RD2-score3-2=79|RD2-score3-3=68|RD2-score3-4=59 |RD2-seed4=3|RD2-team4=[[Kapfenberg Bulls|ece Bulls Kapfenberg]]|RD2-score4-1=92|RD2-score4-2=65|RD2-score4-3=81|RD2-score4-4=61 <!--F--> |RD3-seed1=1|RD3-team1=[[Oberwart Gunners|Redwell Gunners Oberwart]]|RD3-score1-1=61|RD3-score1-2=56|RD3-score1-3=55|RD3-score1-4=72|RD3-score1-5=64 |RD3-seed2=3|RD3-team2=[[Kapfenberg Bulls|ece Bulls Kapfenberg]]|RD3-score2-1=57|RD3-score2-2=66|RD3-score2-3=56|RD3-score2-4=73|RD3-score2-5=73 }}
Quarterfinals | Semifinals | Finals | ||||||||||||||||||||||
1 | Redwell Gunners Oberwart | 75 | 89 | 57 | 79 | 77 | ||||||||||||||||||
5 | WBC Raiffeisen Wels | 84 | 83 | 63 | 62 | 67 | ||||||||||||||||||
4 | Hallmann Vienna | 80 | 66 | 64 | ||||||||||||||||||||
5 | WBC Raiffeisen Wels | 64 | 81 | 69 | ||||||||||||||||||||
1 | Redwell Gunners Oberwart | 61 | 56 | 55 | 72 | 64 | ||||||||||||||||||
3 | ece Bulls Kapfenberg | 57 | 66 | 56 | 73 | 73 | ||||||||||||||||||
2 | Swans Gmunden | 73 | 79 | 68 | 59 | |||||||||||||||||||
3 | ece Bulls Kapfenberg | 92 | 65 | 81 | 61 | |||||||||||||||||||
3 | ece Bulls Kapfenberg | 97 | 95 | |||||||||||||||||||||
6 | Arkadia Traiskirchen Lions | 80 | 82 |
See also
-- -- This module implements many bracket templates -- local p = {} local args = {} local rows = {} local mask = {} local rounds local maxround local legs = {} local compact local byes local hideSeeds local showSeeds local hideHeadings local showThird local offsetThird local compactFinal local sepwidth local aggsep local aggregate local boldwinner local hideomittedscores local RD1seedmap = {} local tcats = '' local function isnotblank(s) return s and s ~= '' end local function isblank(s) return (not s) or (s == '') end local function sumScores(s1, s2) s1 = mw.ustring.gsub(s1 or '', '^[\'%s]*([%d%.]*).-$', '%1') s2 = mw.ustring.gsub(s2 or '', '^[\'%s]*([%d%.]*).-$', '%1') if s1 ~= '' and s2 ~= '' then return tonumber(s1) + tonumber(s2) end return s1 end local function scoreCompare(s1,s2,highwin) local ps1 = mw.ustring.gsub(s1 or '', '^[\'%s]*([%d%.]*)[\'%s]*%([\'%s]*([%d%.]*)[\'%s]*%).-$', '%2') local ps2 = mw.ustring.gsub(s2 or '', '^[\'%s]*([%d%.]*)[\'%s]*%([\'%s]*([%d%.]*)[\'%s]*%).-$', '%2') s1 = mw.ustring.gsub(s1 or '', '^[\'%s]*([%d%.]*).-$', '%1') s2 = mw.ustring.gsub(s2 or '', '^[\'%s]*([%d%.]*).-$', '%1') if s1 ~= '' and s2 ~= '' then s1 = tonumber(s1) s2 = tonumber(s2) if s1 and s2 then if (s1 == s2) then ps1 = tonumber(ps1) ps2 = tonumber(ps2) if ps1 and ps2 then s1 = ps1 s2 = ps2 end end if highwin then return ((s1 > s2) and 1) or ((s1 < s2) and 2) or 0 else return ((s2 > s1) and 1) or ((s2 < s1) and 2) or 0 end end end return 0 end local function unboldParenthetical(s) if s then s = mw.ustring.gsub(s, '(%(%[%[[^%[%]]*%]%]%))', '<span style="font-weight:normal">%1</span>') end return s end local function parseArgs(frame) local fargs = frame.args local pargs = frame:getParent().args; local r = tonumber(fargs.rounds or '') or tonumber(pargs.rounds or '') or 2 local teams = math.pow(2, r) local rdstr = 'RD' .. tostring(r) local rdbstr = 'RD' .. tostring(r) .. 'b' local rdp1str = 'RD' .. tostring(r+1) for i=1,2 do local targs = (i == 1) and pargs or fargs for k,v in pairs(targs) do if type(k) == 'string' then if k:find('^[R3][Dr][d1-9]b?%-[a-z][a-z]*00*') then k = mw.ustring.gsub(k, '^([R3][Dr][d1-9]b?%-[a-z][a-z]*)00*', '%1') if (teams < 10) then tcats = tcats .. '[[Category:Pages using a team bracket with deprecated syntax|P]]' end end if k:find('^' .. rdp1str) then k = mw.ustring.gsub(k, '^' .. rdp1str, '3rd') tcats = tcats .. '[[Category:Pages using a team bracket with deprecated syntax|3]]' elseif k:find('^' .. rdbstr) then k = mw.ustring.gsub(k, '^' .. rdbstr, '3rd') elseif k:find('^' .. rdstr .. '%-[a-z][a-z]*3') then k = mw.ustring.gsub(k, '^' .. rdstr .. '(%-[a-z][a-z]*)3', '3rd%11') elseif k:find('^' .. rdstr .. '%-[a-z][a-z]*4') then k = mw.ustring.gsub(k, '^' .. rdstr .. '(%-[a-z][a-z]*)4', '3rd%12') elseif k:find('^Consol') then k = mw.ustring.gsub(k, '^Consol', '3rd') tcats = tcats .. '[[Category:Pages using a team bracket with deprecated syntax|3]]' elseif k:find('^group[0-9]') then tcats = tcats .. '[[Category:Pages using a team bracket with deprecated syntax|G]]' end end args[k] = v end end if (args['byes'] and (args['byes'] == 'yes' or args['byes'] == 'y')) then tcats = tcats .. '[[Category:Pages using a team bracket with deprecated syntax|B]]' end end local function parseSeedmap(s) s = mw.text.split((s or '0') .. '/', '[%s]*/[%s]*') local teams = math.pow(2, rounds) for r=1,teams do RD1seedmap[r] = 1 end for r=1,#s do if tonumber(s[r] or 'x') then RD1seedmap[tonumber(s[r])] = 0 end end local c = 1 for r=1,teams do if RD1seedmap[r] > 0 then RD1seedmap[r] = c c = c + 1 end end end local function parseLegs(s) s = mw.text.split((s or '1') .. '/', '[%s]*/[%s]*') if aggregate == 'n' or aggregate == 'no' or aggregate == '0' then aggregate = '' end local n = showThird and (rounds + 1) or (rounds) local lastlegs = nil for r=1,n do if s[r] ~= nil and s[r] ~= '' and tonumber(s[r]) then legs[r] = tonumber(s[r]) elseif lastlegs then legs[r] = lastlegs else legs[r] = 1 end lastlegs = legs[r] if legs[r] > 1 and aggregate ~= '' then legs[r] = legs[r] + 1 end end end local function getSeeds() local seeds = {1, 2} local count = 2 local before = false for r = 2, rounds do local max = math.pow(2, r) for i = 1, count do local pos = i * 2 if before then pos = pos - 1 end table.insert(seeds, pos, max - seeds[i * 2 - 1] + 1) before = not before end count = count * 2 end return seeds end local function addTableRow(tbl) return tbl:tag('tr') end local function addBlank(i, css, rowspan, colspan) local row = rows[i] rowspan = rowspan or 1 local jmax = i + rowspan - 1 for j = i, jmax do if rows[j] == nil then rowspan = rowspan - 1 elseif row == nil then row = rows[j] end end local cell = row and row:tag('td') or mw.html.create('td') if rowspan and rowspan > 1 then cell:attr('rowspan', rowspan) end if colspan and colspan > 1 then cell:attr('colspan', colspan) end if css then cell:css(css) end return cell end local function addBorders(cell, topcell, seedorteam, extrasep) if sepwidth > 1 then topcell = true end if seedorteam then cell:css('border', '1px solid #aaa') :css('border-top-width', topcell and '1px' or '0') else cell:css('border-color', '#aaa') :css('border-style', 'solid') :css('border-top-width', topcell and '1px' or '0') :css('border-left-width', (extrasep and '1px') or ((sepwidth > 1) and '1px') or '0') :css('border-right-width', '1px') :css('border-bottom-width', '1px') end end local function addHeading(row, r, text, pad) pad = (pad == nil or pad < 0) and 0 or pad row:tag('td') :attr('colspan', tonumber(hideSeeds and '1' or '2') + legs[r] + pad) :css('text-align', 'center') :css('border', '1px solid #aaa') :css('background-color', args['RD-shade'] or '#f2f2f2') :wikitext(text) :newline() end local function getWidth(param, default) local arg = args[param .. '-width'] if isblank(arg) then arg = default end if tonumber(arg) ~= nil then arg = arg .. 'px' end return arg end local function getTeamArgName(round, type, team) if round > rounds then return string.format('3rd-%s%d', type, team) else if (round == 1) then team = RD1seedmap[team] if team == 0 then return 'NIL' end end return string.format('RD%d-%s%d', round, type, team) end end local function getShadeArg(round, team, s) local argname = getTeamArgName(round, 'shade', team) .. (s and ('-' .. s) or '') local value = args[argname] if isblank(value) then return '#f9f9f9' end return value end local function getScoreArg(round, team, s) local argname = getTeamArgName(round, 'score', team) .. (s and ('-' .. s) or '') local value = args[argname] return value end local function getTeamArg(round, type, team) local argname = getTeamArgName(round, type, team) local value = args[argname] if isblank(value) then return '' end if mw.ustring.find(value, '[%s]*<[%s/]*[Bb][Rr][%s/]*>[%s ]*&[Nn][Bb][Ss][Pp];[%s]*') then tcats = tcats .. '[[Category:Pages using a team bracket with nbsp]]' end return mw.ustring.gsub(value, '[%s]*<[%s/]*[Bb][Rr][%s/]*>[%s ]*&[Nn][Bb][Ss][Pp];[%s]*', '<br/>') end local function isHidden(r, team) return isblank( getTeamArg(r, 'team', team) ) end local function getRoundName(round) local name = args['RD' .. round] if isnotblank(name) then return name end local roundFromLast = rounds - round + 1 if roundFromLast == 1 then return "Finals" elseif roundFromLast == 2 then return "Semifinals" elseif roundFromLast == 3 then return "Quarterfinals" else return "Round of " .. math.pow(2, roundFromLast) end end local function addPath(index, round, top, left, w) local prop = top and 'border-bottom-width' or 'border-top-width' if left and round == 1 then if compact then addBlank(index) else addBlank(index, {['height'] = '7px'}) addBlank(index+1, {['height'] = '7px'}) end return nil else local cell = addBlank(index, {['border-width'] = '0', ['border-style'] = 'solid', ['border-color'] = 'black'}, (not compact) and 2 or 1) if left or round < maxround and not left then cell:css(prop, w or '2px') end return cell end end local function renderTeam(row, round, team, top, otherbye, pad) pad = (pad == nil or pad < 0) and 0 or pad tcs = pad + 1 local seedCell local seedArg = getTeamArg(round, 'seed', team) -- seed value for the paired team local otherteam = team % 2 == 0 and team-1 or team+1 local pairSeedArg = otherbye and '' or getTeamArg(round, 'seed', otherteam) -- show seed if seed is defined for either or both local showSeed = showSeeds or isnotblank(seedArg) or isnotblank(pairSeedArg) if showSeed and (not hideSeeds) then seedCell = row:tag('td') :css('text-align', 'center') :css('background-color', '#f2f2f2') :attr('rowspan', (not compact) and '2' or nil) :wikitext(seedArg) :newline() addBorders(seedCell, top or otherbye, true, false) end local teamArg = getTeamArg(round, 'team', team) if isblank(teamArg) then teamArg = ' ' elseif boldwinner ~= '' then teamArg = unboldParenthetical(teamArg) end if not showSeed and (not hideSeeds) then tcs = tcs + 1 end local teamCell = row:tag('td') :css('background-color', '#f9f9f9') :css('padding', '0 2px') :attr('rowspan', (not compact) and '2' or nil) :attr('colspan', (tcs > 1) and tcs or nil) :wikitext(teamArg) :newline() addBorders(teamCell, top or otherbye, true, false) local scoreCells = {} local wins, otherwins = 0, 0 local sumscore, othersumscore = 0, 0 local teamcolspan = tcs local hassum = false for s = 1, legs[round] do local fw = nil local agg = legs[round] > 1 and s == legs[round] and true or false local score1 = (agg and getScoreArg(round, team, 'agg') or nil) or getScoreArg(round, team, s) or ((legs[round] == 1) and getScoreArg(round, team)) or nil local score2 = (agg and getScoreArg(round, otherteam, 'agg') or nil) or getScoreArg(round, otherteam, s) or ((legs[round] == 1) and getScoreArg(round, otherteam)) or nil local showscore = true if agg and aggregate ~= '' and score1 == nil and hassum then score1 = (aggregate == 'score') and sumscore or ((aggregate == 'legs' or aggregate == 'sets') and wins) or nil end if agg and aggregate ~= '' and score2 == nil and hassum then score2 = (aggregate == 'score') and othersumscore or ((aggregate == 'legs' or aggregate == 'sets') and otherwins) or nil end if (score1 == nil or score1 == '') and (score2 == nil or score2 == '') then if hideomittedscores > 0 and s >= hideomittedscores then teamcolspan = teamcolspan + 1 showscore = false end else hassum = true end if showscore then local winner = scoreCompare(score1, score2, boldwinner ~= 'low') sumscore = sumScores(sumscore, score1) othersumscore = sumScores(othersumscore, score2) if winner == 1 then if boldwinner ~= '' or (agg and (aggregate == 'score' or aggregate == 'legs' or aggregate == 'sets')) then if agg and (aggregate == 'legs' or aggregate == 'sets') and (wins <= (legs[round] - 1)/2) then else fw = 'bold' end end if not (agg and (aggregate == 'score' or aggregate == 'legs' or aggregate == 'sets')) then wins = wins + 1 end elseif winner == 2 then if not (agg and (aggregate == 'score' or aggregate == 'legs' or aggregate == 'sets')) then otherwins = otherwins + 1 end end scoreCells[s] = row:tag('td') :css('text-align', 'center') :css('background-color', getShadeArg(round, team, s)) :css('font-weight', fw) :attr('rowspan', (not compact) and '2' or nil) :wikitext(score1) :newline() addBorders(scoreCells[s], top or otherbye, false, s > 1 and s == legs[round] and aggsep or nil) end end if teamcolspan > 1 then teamCell:attr('colspan', teamcolspan) end if boldwinner ~= '' and wins > otherwins then if (aggregate == 'legs' or aggregate == 'sets') and (wins <= (legs[round] - 1)/2) then else if seedCell then seedCell:css('font-weight', 'bold') end if teamCell then teamCell:css('font-weight', 'bold') end end end end local function renderRound(count, r) local teams = math.pow(2, rounds - r + 1) local step = count / teams local topTeam = true -- is top row in match-up local topPair = true -- is top match-up in pair of match-ups local team = 1 local group = 1 for i = 1, count, step do local offset, height, blank local hideteam = false local otherhideteam = false local hideleftpath = false local hiderightpath = false if r <= byes then hideteam = isHidden(r, team) otherhideteam = isHidden(r, team % 2 == 0 and team-1 or team+1) end if (r == 1) and (RD1seedmap[team] <= 0) then hideteam = true end if (r > 1) and (r <= (byes + 1)) then hideleftpath = isHidden(r-1, 2*team-1) and isHidden(r-1, 2*team) end if (r == 2) and (RD1seedmap[2*team-1] <= 0 and RD1seedmap[2*team] <= 0) then hideleftpath = true end if compactFinal and (r == rounds) then hideleftpath = true end if (tonumber(args['RD' .. (r-1) .. '-RD' .. (r) .. '-path']) or 2) == 0 then hideleftpath = true end if (tonumber(args['RD' .. (r) .. '-RD' .. (r + 1) .. '-path']) or 2) == 0 then hiderightpath = true end -- empty space above or below if compact then offset = topTeam and i or i + 1 height = step - 1 -- leave room for groups for teams other than first and last elseif team == 1 or team == teams then offset = topTeam and i or i + 2 height = step - 2 else offset = topTeam and i + 1 or i + 2 height = step - 3 end if showThird and (r == rounds) and (not topTeam) then height = offset - offsetThird end if compactFinal and (r == (maxround - 1)) then if team == 2 then height = height - 3 end if team == 3 then height = height - 1 offset = offset + 1 addBlank(offset-3, nil, 1, tonumber(hideSeeds and '2' or '3') + legs[r]) addBlank(offset-4) addHeading(rows[offset-4], r + 1, getRoundName(r+1), legs[r] - legs[r+1]) local b = addBlank(offset-4, { ['border-color'] = 'black', ['border-style']= 'solid', ['border-width']= '0'}, 2) b:css('border-right-width', '2px') end end if height > 0 then local pad = 0 local betweenTeams = (topTeam == false and topPair == true) or (topTeam == true and topPair == false) if compactFinal and (r == maxround - 1) then betweenTeams = false end if compactFinal and (r == maxround - 1) and legs[r+1] > legs[r] then pad = legs[r+1] - legs[r] end if compact and betweenTeams then addBlank(offset, nil, height, 1) if topPair then blank = addBlank(offset, nil, 2*height, tonumber(hideSeeds and '1' or '2') + legs[r] + pad) if args['RD' .. r .. '-group' .. group] then blank:wikitext(args['RD' .. r .. '-group' .. group]) blank:css('text-align', 'center') end group = group + 1 end blank = addBlank(offset, {['border-width'] = '0', ['border-style'] = 'solid', ['border-color'] = 'black'}, height, 1) else blank = addBlank(offset, {['border-width'] = '0', ['border-style'] = 'solid', ['border-color'] = 'black'}, height, tonumber(hideSeeds and '3' or '4') + legs[r] + pad) end end -- add bracket local j = topTeam and i + step - (compact and 1 or 2) or i -- add left path addPath(j, r, topTeam, true, hideleftpath and '0' or '2px') if hideteam then addBlank(j, nil, (not compact) and 2 or nil, tonumber(hideSeeds and '1' or '2') + legs[r]) elseif rows[j] then if compactFinal and (r == maxround) then renderTeam(rows[j], r, team, topTeam, otherhideteam, legs[r-1] - legs[r]) elseif compactFinal and (r == maxround - 1) then renderTeam(rows[j], r, team, topTeam, otherhideteam, legs[r+1] - legs[r]) else renderTeam(rows[j], r, team, topTeam, otherhideteam) end end local rightPath = addPath(j, r, topTeam, false, (hiderightpath or hideteam) and '0' or '2px') if not topTeam then topPair = not topPair end if not topPair and r < maxround and (not (hiderightpath or hideteam)) then if blank then blank:css('border-right-width', '2px') end rightPath:css('border-right-width', '2px') end if compactFinal and (r == maxround) then local prop = (team == 1) and 'border-bottom-width' or 'border-top-width' rightPath:css('border-right-width', '2px') :css(prop, '2px') end team = team + 1 topTeam = not topTeam end end local function renderGroups(count, round) local roundFromLast = rounds - round + 1 local groups = math.pow(2, roundFromLast - 2) local step = count / groups local group = 1 local offset = 0 local team = 0 local wdef = (tonumber(args['RD' .. (round) .. '-RD' .. (round + 1) .. '-path']) or 2) .. 'px' local w = wdef for r = 1,round do offset = offset + (hideSeeds and 3 or 4) + legs[r] end for i = step / 2, count, step do local name = 'RD' .. round .. '-group' .. group addBlank(i, {['height'] = '7px'}) addBlank(i+1, {['height'] = '7px'}) addBlank(i, {['text-align'] = 'center'}, 2, offset-2) :wikitext(args[name]) :newline() if (round <= byes) then team = i/(step/2) w = isHidden(round, 2*team-1) and isHidden(round, 2*team) and '0' or wdef end if (round < maxround) then addBlank(i, { ['border-color'] = 'black', ['border-style'] = 'solid', ['border-width'] = '0 ' .. w .. ' 0 0'}) else addBlank(i) end if (round <= byes) then team = team + 1 w = isHidden(round, 2*team-1) and isHidden(round, 2*team) and '0' or wdef end if (round < maxround) then addBlank(i+1, { ['border-color'] = 'black', ['border-style'] = 'solid', ['border-width'] = '0 ' .. w .. ' 0 0'}) else addBlank(i+1) end group = group + 1 end end local function getThirdOffset() local offset = (compact and 1 or 3) * (math.pow(2, rounds) - math.pow(2, rounds-3)) - (compact and 2 or 4) if rounds < 4 then offset = compact and 8 or 17 if rounds < 3 then offset = compact and 6 or 10 if rounds < 2 then offset = compact and 4 or 7 end end end return offset end local function renderThird(count) local k = offsetThird local row = rows[k] local blank if rounds < 2 then blank = addBlank(k-1, {['height'] = '7px'}) end blank = addBlank(k, rounds < 2 and {['height'] = '7px'} or nil) addHeading(row, rounds + 1, args['3rd'] or 'Third place') if rounds < 2 then for i = 1,(compact and 1 or 2) do blank = addBlank(k+i, {['height'] = '7px'}) end end k = k + (compact and 2 or 3) for i = 1,2 do row = rows[k] blank = addBlank(k, rounds < 2 and {['height'] = '7px'} or nil) if row then renderTeam(row, rounds + 1, i, i == 1, false) end if rounds < 2 and not compact then blank = addBlank(k+1, {['height'] = '7px'}) end k = k + (compact and 1 or 2) end end local function maskRows(tbl, count, offsetcount) local rmin = 1 local rmax = count for i = rmin, rmax do mask[i] = false end if showThird then for i = offsetThird,(offsetThird+ (compact and 3 or 5)) do rmax = (i > rmax) and i or rmax mask[i] = true end end for r = 1, maxround do local teams = math.pow(2, rounds - r + 1) local step = count / teams local topTeam = true -- is top row in match-up local team = 1 for i = 1, count, step do local offset, height, blank local hideteam = false if r <= byes then hideteam = isHidden(r, team) end if (r == 1) and (RD1seedmap[team] <= 0) then hideteam = true end if not hideteam then local j = topTeam and i + step - (compact and 1 or 2) or i mask[j] = true end team = team + 1 topTeam = not topTeam end end for r = 1, maxround do local roundFromLast = rounds - r + 1 local groups = math.pow(2, roundFromLast - 2) local step = count / groups local group = 1 for i = step / 2, count, step do if args['RD' .. r .. '-group' .. group] then mask[i] = true mask[i+1] = true end group = group + 1 end end local mmin, mmax = rmax, rmin for i = rmin, rmax do if mask[i] == true then mmin = (i < mmin) and i or mmin mmax = (i > mmax) and i or mmax end end for i = mmin, mmax do rows[i] = addTableRow(tbl) end end local function renderTree(tbl) -- create 3 or 1 rows for every team local count = math.pow(2, rounds) * (compact and 1 or 3) local offsetcount = 2 * (compact and 1 or 3) + (compact and 2 or 3) offsetThird = getThirdOffset() maskRows(tbl, count, offsetcount) if showThird then for i = (count+1), (offsetcount + offsetThird) do if (rounds > 1) then local blank = addBlank(i, nil, 1, tonumber(hideSeeds and '3' or '4') + legs[1]) if compact and (rounds > 2) then blank = addBlank(i, nil, 1, tonumber(hideSeeds and '3' or '4') + legs[2]) end end end end if not compact then -- fill rows with groups for r = 1, rounds - 1 do renderGroups(count, r) end end -- fill rows with bracket for r = 1, maxround do renderRound(count, r) end if showThird then renderThird(count, compact) end end local function renderHeadings(tbl) local titleRow = addTableRow((not hideHeadings) and tbl or mw.html.create('table')) local widthRow = addTableRow(tbl) for r = 1, (compactFinal and (maxround-1) or maxround) do titleRow:tag('td') widthRow:tag('td'):css('width', r > 1 and '5px' or '1px') if compactFinal and r == (maxround-1) then addHeading(titleRow, r, getRoundName(r), legs[r+1] - legs[r]) else addHeading(titleRow, r, getRoundName(r) ) end local seedCell if (not hideSeeds) then seedCell = widthRow:tag('td'):css('width', getWidth('seed', '25px')) end local teamCell = widthRow:tag('td'):css('width', getWidth('team', '150px')) local scoreCells = {} local legsr = legs[r] if compactFinal and r == (maxround-1) then legsr = legs[r+1] > legs[r] and legs[r+1] or legs[r] end for s = 1, legsr do local score_width = '25px' if aggregate and aggregate ~= '' and s > 1 and s == legsr then score_width = getWidth('agg', getWidth('score', score_width)) else score_width = getWidth('score', score_width) end scoreCells[s] = widthRow:tag('td'):css('width', score_width) end titleRow:tag('td') widthRow:tag('td'):css('width', r < rounds and '5px' or '1px') if compact then teamCell:css('height', '7px') else if seedCell then seedCell:wikitext(' ') end teamCell:wikitext(' ') for s = 1, legs[r] do scoreCells[s]:wikitext(' ') end end end end function p.main(frame) parseArgs(frame) rounds = tonumber(args.rounds) or 2 maxround = tonumber(args.maxround) or rounds local teams = math.pow(2, rounds) compact = (args['compact'] and (args['compact'] == 'yes' or args['compact'] == 'y')) compactFinal = ((rounds > 4) and compact and args['compact-final'] and (args['compact-final'] == 'yes' or args['compact-final'] == 'y')) sepwidth = tonumber(args['sepwidth'] or ((args.sets or args.legs) and 1) or (compact and 1) or 2) or 1 aggregate = (args['aggregate'] or ''):lower() aggsep = args['aggsep'] or args['aggregate'] or nil boldwinner = args['boldwinner'] or args['bold_winner'] or '' local autoSeeds = (args['autoseeds'] and (args['autoseeds'] == 'yes' or args['autoseeds'] == 'y')) hideSeeds = (args['seeds'] and (args['seeds'] == 'no' or args['seeds'] == 'n')) showSeeds = (args['seeds'] and (args['seeds'] == 'yes' or args['seeds'] == 'y')) byes = (args['byes'] and (args['byes'] == 'yes' or args['byes'] == 'y') and 1) or (tonumber(args['byes'] or '0') or 0) hideomittedscores = (args['hideomittedscores'] and (args['hideomittedscores'] == 'yes' or args['hideomittedscores'] == 'y') and 1) or (tonumber(args['hideomittedscores'] or '0') or 0) hideHeadings = (args['headings'] and (args['headings'] == 'no' or args['headings'] == 'n')) showThird = isnotblank(args['3rd']) or isnotblank(args['3rd-team1']) or isnotblank(args['3rd-team2']) local align = (args['float'] or args['align'] or ''):lower() local clear = args['clear'] or 'none' parseSeedmap(args['RD1-omit']) parseLegs(args.sets or args.legs) if autoSeeds then -- set default seeds for round 1 local seeds = getSeeds() for i = 1, table.getn(seeds) do local argname = getTeamArgName(1, 'seed', i) if not args[argname] then args[argname] = seeds[i] end end end -- create the table local tbl = mw.html.create('table') :css('border-style', 'none') :css('font-size', '90%') :css('border-collapse', 'separate') :css('border-spacing', '0') :attr('cellpadding', '0') if (args['nowrap'] and (args['nowrap'] == 'yes' or args['nowrap'] == 'y')) then tbl:css('white-space', 'nowrap') end if align == 'right' then tbl:css('float', 'right') if clear ~= 'none' and clear ~= 'no' and clear ~= 'n' then tbl:css('clear', 'right') end tbl:css('margin', '1em 0 1em 2em') elseif align == 'left' then tbl:css('float', 'left') if clear ~= 'none' and clear ~= 'no' and clear ~= 'n' then tbl:css('clear', 'left') end tbl:css('margin', '1em 2em 1em 0') elseif align == 'center' or align == 'centre' then tbl:css('margin', '1em auto') else tbl:css('margin', '1em 2em 1em 1em') end renderHeadings(tbl) renderTree(tbl) if (args['wide'] and (args['wide'] == 'y' or args['wide'] == 'yes')) then return '<div class="noresize" style="overflow:auto">' .. tostring(tbl) .. '</div>' .. tcats end return tostring(tbl) .. tcats end function p.teamBracket(frame) return p.main(frame) end return p