Module:RoundN

local p = { RD = { 'Quarter Finals', 'Semi Finals', 'Final', 'Third Place' } } local output = mw.html.create'table' local rowNum, head = {}, {}

--Provides a convenient naming shortcut up to = for c = 1, 9 do	local N = math.pow(2, c) p['N' .. N] = function(frame) return p.main(frame.args, c)	end p['n' .. N] = p['N' .. N]--to make case insensitive end

function newRow(bodyRow) p.tag = output:tag'tr' p.tag:tag'td' :attr{height = 5} if bodyRow then table.insert(rowNum, bodyRow, p.tag) end end

function drawHead(text, row3rd) (row3rd and rowNum[row3rd]:tag'td':attr{rowspan = 2}	or head.row:tag'td') :attr{colspan = 2} :css{ ['text-align'] = 'center', border = '1px solid #aaa', background = '#f2f2f2' }		:wikitext(text) end

function spacer(width) p.tag:tag'td' :attr{width = width} :wikitext' ' end

function dpBox(v, r)	p.tag = rowNum[r]:tag'td' :wikitext(v or ' ') :attr{rowspan = 2, colspan = 2} end

function boldWin(s1, s2, manual) local result = {} if p.bold and not manual then s1 = tonumber(string.gsub(s1 or , '%D', ), 10) or math.huge s2 = tonumber(string.gsub(s2 or , '%D', ), 10) or math.huge result = ({{s1 < s2, s1 > s2}, {s1 > s2, s1 < s2}})[p.bold] end return result end

function maxSpan(span, start, rows) return math.min(span, math.max(0, rows - start + 1)) end

function teamBox(v, r, f)	p.tag = rowNum[r]:tag'td' :css{ border = '1px solid #aaa', background = ({'gold', 'silver', '#C96', '#f9f9f9'})[f.color or 4] }		:attr{rowspan = 2} :css{['text-align'] = f[1]} :tag(f.bold and 'b' or ):wikitext(' ' .. (v or )) end

function p._main(args, frame) function args:clean(key)--prevent html comments from breaking some args args[key] = args[key] and string.gsub(string.gsub(mw.text.decode(args[key]), '<!.+>', ), '[^%w-;]', ) or nil return args[key] end p.cols = tonumber(args:clean('columns')) p.bold = ({low = 1, high = 2})[args:clean('bold_winner')] local skipMatch, unBold = {}, {}--(skip|manualbold)match# to boolean for k, _ in pairs(args) do		local mType, mNum = string.match(k, '^(%a+)match(%d*)$') mType, mNum = ({skip = skipMatch, manualbold = unBold})[mType], tonumber(mNum) if mType then if mNum then mType[mNum] = args:clean(k) == 'yes' or args[k] == 'true' elseif ({['-']=1,[';']=1})[string.match(args:clean(k), '%d([-;])%d')] then--match ranges when no skipmatch for _, x in ipairs(mw.text.split(args[k], ';')) do					local m = mw.text.split(x, '-') for y = tonumber(m[1] or x) or 1, tonumber(m[2] or m[1] or x) or 0 do						mType[y] = true end end end end end for _, v in ipairs({--more args to boolean		'widescore',		'template',		'color',		'3rdplace',		'omit_blanks',		'scroll_head_unlock',		'previewnumbers'	}) do		if args[v] ~= nil then p[v] = args:clean(v) == 'yes' or args[v] == 'true' end end output :cssText(			(args.scroll_height and 'padding' or 'margin') .. ':1em 2em 1em 1em;border:0;font-size:90%;'			.. (args.style or '')		) :attr{cellpadding = 0, cellspacing = 0} newRow--headings row head.row = p.tag newRow--set column widths for k = 1, p.cols do		if k > 1 then spacer(15) spacer(20) head.row:tag'td':attr{colspan = 2} end spacer(args['team-width'] or 170) spacer(args['score-width'] or (p.widescore and 40) or 30) p.head = args['RD' .. k]			or p.RD[#p.RD + k - p.cols - 1] or ('Round of ' .. math.pow(2, p.cols - k + 1)) drawHead(			k == 1 and p.template and frame:expandTemplate{				title = 'tnavbar-header',				args = {p.head, 'Template:' .. args.name}			} or p.head		) end local step, bump, bumps, RD, m, rows, ns = 1, 0, 0, {tot = 0}, {num = 1, phase = 0}, math.pow(2, p.cols) * 3, mw.title.getCurrentTitle.namespace--Begin output for c = 1, p.cols do		RD.tot = RD.tot + (rows / math.pow(2, c)) / 3 if c > 1 then rowNum[1]:tag'td' :attr{rowspan = bump, colspan = 2} :wikitext' ' end bumps = bump RD.top = m.num for r = 1, rows, 2 do			if c == 1 then newRow(r) newRow(r + 1) end RD.r = r + bumps if rowNum[RD.r] and m.num <= RD.tot then if skipMatch[m.num] then if m.phase == 0 then rowNum[RD.r]:tag'td':attr{rowspan = 6, colspan = 2} :node(c > 1 and mw.html.create'div'								:css{									display = 'inline-block',									['margin-left'] = '-35px',									width = '35px',									height = (p.unit + 6) * 200 / 6 .. '%',									background = '#fff'								}							) if rowNum[RD.r + 6 + maxSpan(bump * 2, RD.r + 6, rows)] then rowNum[RD.r + 6]:tag'td':attr{rowspan = maxSpan(bump * 2, RD.r + 6, rows), colspan = 2} end elseif m.phase == 2 then m.num = m.num + 1 step = step + (p.omit_blanks and 0 or 5) bumps = bumps + maxSpan(bump * 2, RD.r, rows) end elseif m.phase == 0 then dpBox(args[step], RD.r, skipMatch[m.num]) p.tag:node(args.previewnumbers and ns ~= 0 and						mw.html.create'div':css{float = 'left', display = 'inline-block', ['margin-left'] = -(math.floor(math.log10(m.num)) + 2) .. 'ex', border = '1px solid', padding = '0.5ex', background = '#fff'}:wikitext(m.num)					) m.bold = boldWin(args[step + 2], args[step + 4], unBold[m.num]) else teamBox(args[step + (m.phase - 1) * 2 + 1], RD.r, {color = p.color and c == p.cols and m.phase, bold = m.bold[m.phase]}) teamBox(args[step + (m.phase - 1) * 2 + 2], RD.r, {'center', color = p.color and c == p.cols and m.phase, bold = m.bold[m.phase]}) if m.phase == 2 then step = step + 5 m.num = m.num + 1 if bump > 0 and rowNum[RD.r + 2] then p.span = p.cols > c and (bump * 2) or math.max((bump - 1) / 2, 2) bumps = bumps + p.span for s = 2, p.span + 1 do								if c == 1 and (RD.r + s) <= rows then newRow(RD.r + s)								end end rowNum[RD.r + 2]:tag'td':attr{rowspan = p.span, colspan = 2} end r = r + bump end end m.phase = (m.phase + 1) % 3 end end if p.cols > c then--draw lines to next round p.unit = bump + 3 bump = (rows - rows / math.pow(2, c)) / math.pow(2, p.cols - c)			bumps = p.unit + 1 rowNum[1] :tag'td':attr{rowspan = bumps} :tag'td' :attr{rowspan = bump + 4} :css('border-bottom', not skipMatch[RD.top] and '1px solid' or nil) RD.n = 0 for r = bumps + 1, rows, p.unit * 2 do				p.tag = rowNum[r]:tag'td' if ((r - bumps - 1) / (p.unit * 2)) % 2 == 0 then RD.t = RD.t2 or ((skipMatch[RD.top] and 1 or 0) + (skipMatch[RD.top + 1] and 2 or 0)) RD.n = RD.n + 2 RD.t2 = (skipMatch[RD.top + RD.n] and 1 or 0) + (skipMatch[RD.top + RD.n + 1] and 2 or 0) if RD.t == 0 then p.tag :attr{rowspan = maxSpan(p.unit * 2, r, rows)} :css{ border = '3px solid', ['border-left'] = 0 }					else p.tag :attr{rowspan = maxSpan(p.unit, r, rows)} :cssText(RD.t == 2 and 'border-width:3px 3px 0 0;border-style:solid' or nil) rowNum[r + p.unit]:tag'td' :attr{rowspan = maxSpan(p.unit, r + p.unit, rows)} :cssText(RD.t == 1 and 'border-width:0 3px 3px 0;border-style:solid' or nil) end rowNum[r + p.unit]:tag'td' :attr{rowspan = maxSpan(p.unit * 4, r + p.unit, rows)} :css((RD.t2 < 3 and rowNum[r + p.unit * 5] or RD.t < 3) and {							['border-width'] = (RD.t < 3 and 2 or 0) .. 'px 0 ' .. (RD.t2 < 3 and rowNum[r + p.unit * 5] and '1px' or 0),							['border-style'] = 'solid'						} or {}) else p.tag:attr{rowspan = maxSpan(p.unit * 2, r, rows)} end end end end if p['3rdplace'] or p.cols > 3 and p['3rdplace'] == nil then--begin 3rd place RD.r = rows / 2 + 4 + (p.span or 3) for r = rows + 1, RD.r + 7 do			newRow(r) end if rowNum[rows + 1] and p.cols > 1 then rowNum[rows + 1]:tag'td':attr{ rowspan = RD.r + 7 - rows, colspan = (p.cols - 1) * 4 }		end drawHead(args.Consol or args['RD' .. (p.cols + 1)] or p.RD[4], RD.r)		dpBox(args[step], RD.r + 2) m.bold = boldWin(args[step + 2], args[step + 4], unBold[m.num]) for k, v in ipairs({			{4, {color = p.color and 3, bold = m.bold[1]}},			{4, {'center', color = p.color and 3, bold = m.bold[1]}},			{6, {bold = m.bold[2]}},			{6, {'center', bold = m.bold[2]}}		}) do			teamBox(args[step + k], RD.r + v[1], v[2]) end end return args.scroll_height and mw.html.create'div' :cssText'border-bottom:1px solid #eee;display:inline-block' :node(not p.scroll_head_unlock and mw.html.create'div'				:css{					overflow = 'hidden',					height = '3em',					['border-bottom'] = 'inherit',					['margin-right'] = '17px'				}				:node(mw.clone(output))			) :tag'div' :cssText('overflow-y:scroll;max-height:'					.. args.scroll_height .. (string.match(args.scroll_height, '^%d*$') and 'px' or '')				) :node(not p.scroll_head_unlock and					output:css('margin-top', '-3em')					or output				) :done or output end

function p.main(frame, columns) local args = require'Module:Arguments'.getArgs(frame, {trim = false}) args.columns = columns or args.columns return p._main(args, frame) end

return p