mNo edit summary Tag: Reverted |
mNo edit summary |
||
(7 intermediate revisions by the same user not shown) | |||
Line 8: | Line 8: | ||
local args = getArgs(frame) | local args = getArgs(frame) | ||
if args.teams == nil then return 'Have to enter a "teams" value as a Bracket template paramater' end | if args.teams == nil then return 'Have to enter a "teams" value as a Bracket template paramater' end | ||
-- if best-of set to bracket, then set VariableLua for it for entire bracket to use | |||
if args.bestof then VariablesLua.vardefine('bestof', args.bestof) end | |||
if args.solo then VariablesLua.vardefine('solo', 1) end | |||
if args.twitch then VariablesLua.vardefine('twitch', args.twitch) end | |||
if args.youtube then VariablesLua.vardefine('youtube', args.youtube) end | |||
-- set const values | -- set const values | ||
local roundW = args.roundW or 180 | local roundW = args.roundW or 180 | ||
Line 34: | Line 39: | ||
local upperRounds = {} | local upperRounds = {} | ||
local lowerRounds = {} | local lowerRounds = {} | ||
-- Go through upper bracket to see how many rounds and matches it has | -- Go through upper bracket to see how many rounds and matches it has | ||
while tonumber(matchAmount) > 1 do | while tonumber(matchAmount) > 1 do | ||
Line 68: | Line 73: | ||
local nextUpperMatches = upperRounds[ubRound + 1] and upperRounds[ubRound + 1].matches or 0 | local nextUpperMatches = upperRounds[ubRound + 1] and upperRounds[ubRound + 1].matches or 0 | ||
local round = lower['R' .. lbRound] ~= nil and mw.text.jsonDecode(lower['R' .. lbRound]) or {} | local round = lower['R' .. lbRound] ~= nil and mw.text.jsonDecode(lower['R' .. lbRound]) or {} | ||
local roundTitle = round.title or upperMatches ~= 1 and ' | local roundTitle = round.title or upperMatches ~= 1 and 'LB Round ' .. lbRound or 'LB Final' | ||
-- If amount of matches is manually entered, then overwrite | -- If amount of matches is manually entered, then overwrite | ||
if round.matches then lowerMatches = round.matches end | if round.matches then lowerMatches = round.matches end | ||
Line 102: | Line 107: | ||
-- If ladvance is set then add empty round to UB round 2 | -- If ladvance is set then add empty round to UB round 2 | ||
if args.ladvance then table.insert(upperRounds, 2, {matches = 0}) end | if args.ladvance then table.insert(upperRounds, 2, {matches = 0}) end | ||
-- draw upper bracket | -- draw upper bracket | ||
local upperOffset = 0 | |||
for i = 1, #upperRounds do | for i = 1, #upperRounds do | ||
local roundNode = mw.html.create('div'):addClass('bracket-round') | local roundNode = mw.html.create('div'):addClass('bracket-round') | ||
local round = upperRounds[i] | local round = upperRounds[i] | ||
local argsRound = upper['R' .. i] ~= nil and mw.text.jsonDecode(upper['R' .. i]) or nil | local argsRound = upper['R' .. i - upperOffset] ~= nil and mw.text.jsonDecode(upper['R' .. i - upperOffset]) or nil | ||
local matches = round.matches | local matches = round.matches | ||
if round.matches == 0 then upperOffset = upperOffset + 1 end | |||
-- Add round header to container | -- Add round header to container | ||
ubheader:node(mw.html.create('div'):wikitext(round.title)) | ubheader:node(mw.html.create('div'):wikitext(round.title)) | ||
Line 182: | Line 190: | ||
end | end | ||
-- Add grand final | -- Add grand final | ||
local maxMatches = 0 | local maxMatches = 0 | ||
for _, obj in ipairs(upperRounds) do | for _, obj in ipairs(upperRounds) do | ||
Line 190: | Line 197: | ||
end | end | ||
local grandFinal = mw.html.create('div'):addClass('grand-final'):css('width', roundW .. 'px'):css('height', (maxMatches * 56 + (maxMatches - 1) * 10 + 26 + 10) .. 'px') | local grandFinal = mw.html.create('div'):addClass('grand-final'):css('min-width', roundW .. 'px'):css('width', roundW .. 'px'):css('height', (maxMatches * 56 + (maxMatches - 1) * 10 + 26 + 10) .. 'px') | ||
grandFinal:node(mw.html.create('div'):addClass('bracket-header'):node(mw.html.create('div'):wikitext('Grand Final'))) | grandFinal:node(mw.html.create('div'):addClass('bracket-header'):node(mw.html.create('div'):wikitext('Grand Final'))) | ||
if args.final == nil then | if args.final == nil then | ||
grandFinal:node(mw.html.create('div'):addClass('match'):node(html.team('')):node(html.team(''))) | grandFinal:node(mw.html.create('div'):addClass('match'):node(html.team('')):node(html.team(''))) | ||
else | else | ||
grandFinal:node(mw.html.create('div'):addClass('grand-final-round'):node( | grandFinal:node(mw.html.create('div'):addClass('grand-final-round'):node(args.final)) | ||
end | end | ||
container:node(grandFinal) | container:node(grandFinal) | ||
end | end | ||
Line 207: | Line 213: | ||
lbrounds:css('grid-template-columns', 'repeat(' .. maxRounds .. ', ' .. roundW .. 'px)') | lbrounds:css('grid-template-columns', 'repeat(' .. maxRounds .. ', ' .. roundW .. 'px)') | ||
wrapper:node(ubheader):node(ubrounds):node(lbheader):node(lbrounds) | wrapper:node(ubheader):node(ubrounds) | ||
if args.lteams then wrapper:node(lbheader):node(lbrounds) end | |||
if args.bestof then VariablesLua.vardefine('bestof', 0) end | |||
if args.twitch then VariablesLua.vardefine('twitch', 0) end | |||
if args.youtube then VariablesLua.vardefine('youtube', 0) end | |||
return container | return container | ||
end | end |
Latest revision as of 23:31, 6 November 2023
Documentation for this module may be created at Module:Bracket/doc
local getArgs = require('Module:Arguments').getArgs
local html = require('Module:MatchHTML')
local Bracket = {}
local VariablesLua = mw.ext.VariablesLua
function Bracket.main(frame)
local args = getArgs(frame)
if args.teams == nil then return 'Have to enter a "teams" value as a Bracket template paramater' end
-- if best-of set to bracket, then set VariableLua for it for entire bracket to use
if args.bestof then VariablesLua.vardefine('bestof', args.bestof) end
if args.solo then VariablesLua.vardefine('solo', 1) end
if args.twitch then VariablesLua.vardefine('twitch', args.twitch) end
if args.youtube then VariablesLua.vardefine('youtube', args.youtube) end
-- set const values
local roundW = args.roundW or 180
-- create all the html parent elements
local container = mw.html.create('div'):addClass('bracket')
if args.lteams then container:addClass('de') end
local wrapper = mw.html.create('div'):addClass('bracket-wrapper')
local ubheader = mw.html.create('div'):addClass('bracket-header')
local ubrounds = mw.html.create('div'):addClass('bracket-rounds')
local lbheader = mw.html.create('div'):addClass('bracket-header')
local lbrounds = mw.html.create('div'):addClass('bracket-rounds')
container:node(wrapper)
-- get max amount of matches for the first round
local maxUbroundAmount = args.rounds or math.ceil(math.log(args.teams) / math.log(2))
local ubroundAmount = 0
local lbroundAmount = 0
local upper = args.upper ~= nil and mw.text.jsonDecode(args.upper) or {}
local lower = args.lower ~= nil and mw.text.jsonDecode(args.lower) or {}
local lteams = tonumber(args.lteams)
local matchAmount = (2^maxUbroundAmount)
local upperMatches = args.teams and args.teams / 2 or 0
local lowerMatches = lteams and lteams / 2 or 0
local dropping = upperMatches
local upperRounds = {}
local lowerRounds = {}
-- Go through upper bracket to see how many rounds and matches it has
while tonumber(matchAmount) > 1 do
ubroundAmount = ubroundAmount + 1
local round = upper['R' .. ubroundAmount] ~= nil and mw.text.jsonDecode(upper['R' .. ubroundAmount]) or nil
local roundTitle = (round and round.title) or lteams and 'Upper round ' .. ubroundAmount or 'Round ' .. ubroundAmount
-- if round.matches is lower than previous round divided by 2
if (round and round.matches) and round.matches * 2 < matchAmount then
matchAmount = matchAmount / 2
else
matchAmount = (round and round.matches) or matchAmount / 2
end
upperRounds[ubroundAmount] = {
matches = tonumber(matchAmount),
title = roundTitle
}
end
-- If lower bracket exists then populate lowerRounds and adjust upperRounds
if lteams ~= nil then
local ubRound = 1
if lteams > 0 then ubRound = 0 end
local lbRound = 1
local lower = args.lower ~= nil and mw.text.jsonDecode(args.lower) or {}
local upperMatches = upperRounds[1].matches
local lowerMatches = lteams > 0 and lteams / 2 or upperMatches / 2
if args.ladvance then lowerMatches = lowerMatches + args.ladvance / 2 end
-- Start loop
while #upperRounds >= ubRound and lowerMatches >= 1 do
upperMatches = (upperRounds[ubRound] and upperRounds[ubRound].matches) or 0
local nextUpperMatches = upperRounds[ubRound + 1] and upperRounds[ubRound + 1].matches or 0
local round = lower['R' .. lbRound] ~= nil and mw.text.jsonDecode(lower['R' .. lbRound]) or {}
local roundTitle = round.title or upperMatches ~= 1 and 'LB Round ' .. lbRound or 'LB Final'
-- If amount of matches is manually entered, then overwrite
if round.matches then lowerMatches = round.matches end
-- If lowerMatches is exactly 2 times lower than upperMatches
if lowerMatches * 2 == upperMatches then
table.insert(lowerRounds, Bracket.newRound(lowerMatches, roundTitle))
ubRound = ubRound + 1
-- If lowerMatches is same as upperMatches
elseif lowerMatches == upperMatches then
table.insert(lowerRounds, Bracket.newRound(lowerMatches, roundTitle))
if upperMatches ~= 1 then
table.insert(upperRounds, ubRound + 1, {matches = 0})
nextUpperMatches = 0
end
ubRound = ubRound + 1
-- Else if upperMatches is lower
elseif upperMatches < lowerMatches then
table.insert(lowerRounds, Bracket.newRound(lowerMatches, roundTitle))
end
lowerMatches = upperMatches == 0 and lowerMatches or nextUpperMatches / 2 + lowerMatches / 2
if lbRound == 1 and args.ladvance then lowerMatches = lowerMatches / 2 end
lbRound = lbRound + 1
if upperMatches == 0 then ubRound = ubRound + 1 end
end
end
-- If lower and upper bracket both start with same amount of teams, then shift upper bracket one column to the right
if args.teams == args.lteams then
table.insert(upperRounds, 1, {matches = 0})
end
-- If ladvance is set then add empty round to UB round 2
if args.ladvance then table.insert(upperRounds, 2, {matches = 0}) end
-- draw upper bracket
local upperOffset = 0
for i = 1, #upperRounds do
local roundNode = mw.html.create('div'):addClass('bracket-round')
local round = upperRounds[i]
local argsRound = upper['R' .. i - upperOffset] ~= nil and mw.text.jsonDecode(upper['R' .. i - upperOffset]) or nil
local matches = round.matches
if round.matches == 0 then upperOffset = upperOffset + 1 end
-- Add round header to container
ubheader:node(mw.html.create('div'):wikitext(round.title))
for j = 1, matches do
local match = argsRound and argsRound['M' .. j] or nil
-- if no existing match html, then create it from scratch
if match == nil then
roundNode:node(mw.html.create('div'):addClass('match'):node(html.team('')):node(html.team('')))
-- roundNode:node(mw.html.create('div'):addClass('match'):node(team1):node(team2):node(html.team('')):node(html.team('')))
else
roundNode:node(match)
end
end
--see if next rounds matchAmount is equal to or greater than current rounds
local nextRound = upperRounds[i + 1] or {}
if tonumber(matches) <= tonumber(nextRound.matches or 0) then
roundNode:addClass('round-offset')
else
if tonumber(matches) ~= 1 or lteams ~= nil then
roundNode:addClass('conn-r')
end
end
-- If previous round was empty
if upperRounds[i - 1] and upperRounds[i - 1].matches == 0 then
if i ~= 2 then
roundNode:addClass('long')
else
roundNode:addClass('first')
end
end
ubrounds:node(roundNode)
end
-- draw lower bracket
if args.lteams then
for i = 1, #lowerRounds do
local roundNode = mw.html.create('div'):addClass('bracket-round')
local round = lowerRounds[i]
local argsRound = lower['R' .. i] ~= nil and mw.text.jsonDecode(lower['R' .. i]) or nil
local matches = round.matches
-- Add round header to container
lbheader:node(mw.html.create('div'):wikitext(round.title))
for j = 1, matches do
local match = argsRound and argsRound['M' .. j] or nil
-- if no existing match html, then create it from scratch
if match == nil then
roundNode:node(mw.html.create('div'):addClass('match'):node(html.team('')):node(html.team('')))
else
roundNode:node(match)
end
end
--see if next rounds matchAmount is equal to or greater than current rounds
local nextRound = lowerRounds[i + 1] or {}
if tonumber(matches) <= tonumber(nextRound.matches or 0) then
roundNode:addClass('round-offset')
else
if tonumber(matches) ~= 1 or lteams ~= nil then
roundNode:addClass('conn-r')
end
end
-- Add adjusting classes for connectors if next round is round offset
if lowerRounds[i + 1] and lowerRounds[i + 2] and lowerRounds[i + 1].matches == lowerRounds[i + 1].matches then
roundNode:addClass('conn-adj')
end
-- If previous round was empty
if lowerRounds[i - 1] and lowerRounds[i - 1].matches == 0 then roundNode:addClass('long') end
if i == #lowerRounds then roundNode:addClass('last') end
lbrounds:node(roundNode)
end
-- Add grand final
local maxMatches = 0
for _, obj in ipairs(upperRounds) do
if obj.matches and obj.matches > maxMatches then
maxMatches = obj.matches
end
end
local grandFinal = mw.html.create('div'):addClass('grand-final'):css('min-width', roundW .. 'px'):css('width', roundW .. 'px'):css('height', (maxMatches * 56 + (maxMatches - 1) * 10 + 26 + 10) .. 'px')
grandFinal:node(mw.html.create('div'):addClass('bracket-header'):node(mw.html.create('div'):wikitext('Grand Final')))
if args.final == nil then
grandFinal:node(mw.html.create('div'):addClass('match'):node(html.team('')):node(html.team('')))
else
grandFinal:node(mw.html.create('div'):addClass('grand-final-round'):node(args.final))
end
container:node(grandFinal)
end
local maxRounds = #upperRounds <= #lowerRounds and #lowerRounds or #upperRounds
ubheader:css('grid-template-columns', 'repeat(' .. maxRounds .. ', ' .. roundW .. 'px)')
ubrounds:css('grid-template-columns', 'repeat(' .. maxRounds .. ', ' .. roundW .. 'px)')
lbheader:css('grid-template-columns', 'repeat(' .. maxRounds .. ', ' .. roundW .. 'px)')
lbrounds:css('grid-template-columns', 'repeat(' .. maxRounds .. ', ' .. roundW .. 'px)')
wrapper:node(ubheader):node(ubrounds)
if args.lteams then wrapper:node(lbheader):node(lbrounds) end
if args.bestof then VariablesLua.vardefine('bestof', 0) end
if args.twitch then VariablesLua.vardefine('twitch', 0) end
if args.youtube then VariablesLua.vardefine('youtube', 0) end
return container
end
function Bracket.newRound(matches, title)
return {
matches = matches,
title = title
}
end
return Bracket