Questa pagina è protetta dallo spostamento
Questa pagina è protetta

Modulo:Torneo

Da Wikipedia, l'enciclopedia libera.
Vai alla navigazione Vai alla ricerca

Questo modulo implementa una generica rappresentazione visuale di un torneo a eliminazione singola con un qualunque numero di round. È utilizzato dal template {{Torneo}}.

Uso

{{#invoke: TeamBracket | teamBracket
|rounds      =

|seed-width  =
|team-width  =
|score-width =

|RD1         =
|RD1-group1  =
|RD1-seed1   =
|RD1-team1   =
|RD1-score1  =
 ...
}}

Parametri

I parametri sono i seguenti:

  • rounds: il numero di round del torneo (se non specificato 2)
  • RDn: Nome del turno n. I nomi di default sono nell'ordine dall'ultimo al primo: "Finale", "Semifinali", "Quarti", "Ottavi". Se ci sono turni prima ancora degli ottavi il nome di default è "5° turno", "6° turno", ... e così via.
  • RDn-groupm: nome del gruppo m nel turno n. Per gruppo si intende un insieme di due incontri
  • RDn-seedm: il piazzamento (seed) della squadra/giocatore m nel turno n. m viene completato con 0 a sinistra.
  • RDn-teamm: il nome della squadra/giocatore m nel round n. Se uno dei due nomi di squadra/giocatore è bye il match non viene disegnato. m viene completato con 0 a sinistra.
  • RDn-scorem: il punteggio della squadra/giocatore m nel turno n.
  • scores: il numero di incontri per round. Può essere un singolo numero o una serie di numeri separati da virgola. Se è un singolo numero questo viene considerato come il numero di incontri per ogni round, se una serie di numeri questi sono considerati come la sequenza di incontri per ogni round (se non viene specificato un numero di incontri per tutti i round l'ultimo numero viene assegnato a tutti i round rimanenti).

Parametri di stile:

  • compact: indicare yes o per una rappresentazione compatta (in questo caso sono disabilitati i gruppi).
  • seed-width: larghezza della cella che contiene il piazzamento (seed). Deve essere una larghezza CSS valida (per esempio 25px o 1em) oppure un numero (in questo caso viene considerato come una larghezza in pixel). Valore di default 25px.
  • team-width: larghezza della cella per i nomi delle squadre. Deve essere una larghezza CSS valida (per esempio 25px o 1em) oppure un numero (in questo caso viene considerato come una larghezza in pixel). Valore di default 25px.
  • score-width: larghezza della cella per i punteggi. Deve essere una larghezza CSS valida (per esempio 25px o 1em) oppure un numero (in questo caso viene considerato come una larghezza in pixel). Valore di default 25px.
  • seeds: no per nascondere tutti i seed, per visualizzare tutti i seed (per quelli non assegnati viene generato un valore di default). Se non viene valorizzato i seed sono visualizzati assegnati, altrimenti nascosti.
  • bold_winner: Il template rende automaticamente in grassetto il vincitore. Se questo parametro viene settato a no questo comportamento viene disabilitato.
  • medals: Il template assegna automaticamente uno sfondo  oro ,  argento  e  bronzo  al primo, secondo e terzo classificato. Se questo parametro viene settato a no questo comportamento viene disabilitato. Se a low viene considerata vincente chi ha ottenuto il punteggio minore.

Esempi

No seeds

{{#invoke: TeamBracket | teamBracket
|rounds    = 2
|RD1-seed1 =
|RD1-seed2 =
|RD1-seed3 =
|RD1-seed4 =
}}
Semifinali Finale
      
 
 
 
 
 
 

Gruppi

{{#invoke: TeamBracket | teamBracket
|rounds     = 3
|RD1-group1 = Pacific
|RD1-group2 = Mountain
|RD2-group1 = West
}}
Quarti di finale Semifinali Finale
         
 
 
 
Pacific
 
 
 
 
West
 
 
 
 
Mountain
 
 
 

--
-- This module will implement {{TeamBracket}}
--
require('strict')

local getArgs = require('Module:Arguments').getArgs

local p = {}
local yes_replies = { 'yes', 'y', 's', 'si', 'sì'}
local no_replies = { 'n', 'no'}
local debug = false

local style = {
	table = "border-style:none;font-size:90%;margin:1em 2em 1em 1em;border-collapse:separate;border-spacing:0",
	seed_cell = "background-color:#f2f2f2;border:1px solid #aaa;text-align:center;",
	team_cell = "background-color:#f2f2f2;border:1px solid #aaa;text-align:left;padding:0 2px",
	score_cell ="background-color:#f9f9f9;border:1px solid #aaa;text-align:center;",
	header_third_place = "text-align:center;border:1px solid #aaa;background-color:#f2f2f2",
	header_cell = "text-align:center;border:1px solid #aaa;background-color:#f2f2f2",
	path_bottom = "border:0 solid black;border-bottom-width:2px;",
	path_rigth_top = "border:0 solid black;border-top-width:1px;border-right-width:2px;",
	path_right_bottom = "border:0 solid black;border-bottom-width:1px;border-right-width:2px;",
	path_top = "border:0 solid black;border-top-width:2px;",
	group = "text-align:center", 
	winner = 'font-weight:bold',
	first_place = 'background-color:#F7F6A8',
	second_place = 'background-color:#DCE5E5',
	third_place = 'background-color:#FFDAB9',
	row_height = "3px", 
	buffer_sx_width = "5px",
	seed_width = "25px",
	team_width = "190px",
	score_width = "25px",
	row_width = "10px"
}

if debug then
	style.group = style.group .. ";background-color:green"
	style.path_bottom = style.path_bottom .. ";background-color:#F08080"
	style.path_top= style.path_top .. ";background-color:#F08080"
	style.path_rigth_top= style.path_rigth_top .. ";background-color:#F08080"
	style.path_right_bottom= style.path_right_bottom .. ";background-color:#F08080"
end

--[[ ===============================================================================
Ritorna true se needle è lista haystack, altrimenti ritorna false
	===============================================================================]]
local function in_array( needle, haystack )
	if needle == nil then return false; end
	for n,v in ipairs( haystack ) do
		if v == needle then return true; end
	end
	return false;
end

--[[ ===============================================================================
Oggetto per generare un TeamBracket
- args: array dei parametri passati al modulo
===============================================================================]]
local TeamBracket = {}

function TeamBracket:new(args)

	local self = {}
	setmetatable(self, { __index = TeamBracket,
						 __tostring = function(t) return self:__tostring() end })

	self.args = args
	self.rounds = tonumber(self.args['rounds']) or 2
	self.teams = math.pow(2, self.rounds)
	self.compact = in_array(self.args['compact'], yes_replies)
	self.hideSeeds = in_array(self.args['seeds'], no_replies)
	self.showSeeds = in_array(self.args['seeds'], yes_replies)
	local padding = '%0' .. ((self.teams < 10) and 1 or 2) .. 'd'
	self.argname_pattern = 'RD%d-%s' .. padding
	self.scorename_pattern = 'RD%d-score' .. padding
	local autobold_par = self.args['bold_winner'] or ''
	self.bold_winner = not in_array(autobold_par, no_replies)
	self.low_winner = self.bold_winner and (autobold_par == 'low') 
	self.medals = self.bold_winner and not in_array(self.args['medals'], no_replies)
	-- load number of scores for each round
	self.scores =  {}
	local scores_raw = self.args.scores or '1'
	local max_scores = 1
	for i,score_value in ipairs(mw.text.split(scores_raw, ',')) do
		self.scores[i] = tonumber(score_value) or 1
		if self.scores[i] > max_scores then max_scores = self.scores[i] end
	end
	local last_scores = self.scores[#self.scores]
	for i =#self.scores+1, self.rounds do
		self.scores[i] = last_scores
	end
	if max_scores > 1 then
		self.scorename_pattern = self.scorename_pattern .. "-%d"
	end
	-- custom style
	style.winner = self.args.style_medal or style.winner
	style.first_place = self.args.style_first_place or style.first_place
	style.second_place = self.args.style_second_place or style.second_place
	style.third_place = self.args.style_third_place or style.third_place
	style.header_cell = self.args.style_header or style.header_cell
	style.header_third_place = self.args.style_header_third_place or style.header_third_place
	style.seed_width = self:getWidth('seed', style.seed_width)
	style.team_width = self:getWidth('team', style.team_width)
	style.score_width = self:getWidth('score', style.score_width)
	-- set default seeds for round 1
	if not(self.hideSeeds) then
		local seeds = self:getSeeds()
		local argname
		for i = 1, table.getn(seeds) do
			argname = self:getTeamArgName(1, 'seed', i)
			if not args[argname] then
				args[argname] = seeds[i]
			end
		end
	end
	self.tbl = mw.html.create('table'):cssText(style.table)
	if in_array(args['nowrap'], yes_replies) then
		self.tbl:css('white-space', 'nowrap')
	end
	self.rows = { }
	if self.compact then self.tbl:attr('cellpadding', '0') end
	self.last_element = {}
	self.rows = {}
	self.current_col = 0
	self.not_draw_top = false
	self:renderHeading()
	self:renderTree()
	return self
end

--[[ ===============================================================================
-- collassa l'oggetto in una stringa contenente il wikicodice per generare l'albero
===============================================================================]]
function TeamBracket:__tostring()
	return tostring(self.tbl)
end

--[[ ===============================================================================
Genera i valori di default dei seeds
===============================================================================]]
function TeamBracket:getSeeds()
	local seeds = {1, 2}
	local count = 2
	local before = false
	for r = 2, self.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

--[[ ===============================================================================
Ritorna il valore per i parameri di larghezza (seed-widt, score-width, team-width)
===============================================================================]]
function TeamBracket:getWidth(param, default)
	local arg = self.args[param .. '-width']
	if not arg then return default end
	return arg .. ((tonumber(arg) and 'px') or '')
end

--[[ ===============================================================================
Se fino alla riga row, colonna col-1 non sono ancora stati aggiunti elementi aggiunte
una cella vuota dall'ultima colonna usta dalla riga. 
Aggiorna quindi il conteggio delle colonne usate alla posizione colonna +width 
Il valore di default di width è 0 
=============================================================================== --]]
function TeamBracket:addGap(row, col, width, debug_info)
	width = width or 1
	if self.last_element[row] + 1 < col  then
		local gap = tostring(col - self.last_element[row] - 1)
		local cell=self.rows[row]:tag('td'):css('background-color', (debug and '#F5F5DC') or ''):attr('colspan', gap)
		if debug then
			cell:wikitext(string.format('<div style="text-align:center;" title="row=%d, colonna:%d, last_col=%d, width:%d, gap:%s, last_col_set:%d, round:%d, deb:%s">info</div>',
							row, col, self.last_element[row], width, gap, col+width, self.current_round, debug_info or ''))
		end
	end
	self.last_element[row] = col + width - 1 
end

--[[ ===============================================================================
Ritorna il nome completo del parametro 'argname' della squadra 'team' nel round 'round' 
Per esempio getTeamArgName(1, 'seed', 3) ritorna 'RD1-seed3' o ''RD1-seed03' se ci sono
10 squadre o più
===============================================================================]]
function TeamBracket:getTeamArgName(round, argname, team)
	return string.format(self.argname_pattern, round, argname, team)
end

--[[ ===============================================================================
Ritorna il valore del parametro 'argname' della squadra 'team' nel round 'round', 
Per esempio getTeamArg(1, 'seed', 3) ritorna il valore del parametro 'RD1-seed3'
===============================================================================]]
function TeamBracket:getTeamArg(round, argname, team)
	return self.args[self:getTeamArgName(round, argname, team)]
end

--[[ ===============================================================================
Ritorna il valore dello score dato il round, la posizione nel round (team) e il 
progressivo dell'incontro.
===============================================================================]]
function TeamBracket:getScoreArg(round, team, score)
	return self.args[string.format(self.scorename_pattern, round, team, score)]
end

--[[ ===============================================================================
Ritorna il nome del round 'round' o il suo nome di default se non è precisato.
===============================================================================]]
function TeamBracket:getRoundName(round)
	local name = self.args['RD' .. round]
	if name then return name end
	local round_names = {"Finale", "Semifinali", "Quarti", "Ottavi"}
	local roundFromLast = self.rounds - round + 1
	if roundFromLast < 5 then
		return round_names[roundFromLast]
	else
		return tostring(round) .. "° turno"
	end
end

--[[ ===============================================================================
Aggiunge le righe grafiche di congiunzione delle celle per la riga index del
turno round. top e left indicano se deve essere generata rispettivamente la riga
sinistra o quella superiore
- row1 = prima riga del match superiore da cui esce il path
- row2 = prima riga del match inferiore da cui esce il path
- row_gap = ampiezza del path
- col = colonna in cui inizia il path
row1 nullo significa che il path parte solo da row2 e viceversa. Se entrambi sono
nulli la funzione non disegna niente.
===============================================================================]]
function TeamBracket:addPath(row1, row2, row_gap, next_match)

	local col = self.current_col + self.current_width  
	local half_gap = row_gap / 2
	if not (row1 or row2) then return end
	self.render_match[self.current_round+1][next_match] = true
	-- first half
	if row1 then 
		self.rows[row1+1]:tag('td'):cssText(style.path_bottom)
		for r = row1+1, row1+3 do self.last_element[r] = col end
		for r = row1+4, row1+4+half_gap-1 do self:addGap(r, col, 1, 'ap1') end
		self.rows[row1+2]:tag('td')
			:attr('rowspan', half_gap + 2)
			:cssText(style.path_rigth_top)
	end
	--second half
	if row2 then
		self.rows[row2+2]:tag('td'):cssText(style.path_top)
		for r = row2, row2+2 do self.last_element[r] = col end
		for r = row2-half_gap, row2-1 do self:addGap(r, col, 1, 'ap2') end
		self.rows[row2-half_gap]:tag('td')
			:attr('rowspan', half_gap+2)
			:cssText(style.path_right_bottom)
	end
	local middle_row
	middle_row  = (row1 and (row1 + 2 + half_gap)) or (row2 - half_gap -2)
	for r = middle_row-1, middle_row+2 do self:addGap(r, col+1, 1, 'ap3') end
	--self:addGap(middle_row, col+1, 1, 'ap3')
	--self:addGap(middle_row+1, col+1, 1, 'ap3')
	self.rows[middle_row]:tag('td'):cssText(style.path_bottom):attr('rowspan', '2')
	self.rows[middle_row+2]:tag('td'):cssText(style.path_top):attr('rowspan', '2')
end

--[[ ------------------------------------------------------------
Compare score values and return and return the winner of the match 
(team with majority of win, 0 mean parity, 1 fist team win, 2
second team win) and and array with winner for single scores (for
each single score 0 parity, 1 first team win, 2 second team win.
 ------------------------------------------------------------ --]]
function TeamBracket:getWinner(first_team_number)
	local victories1 = 0
	local victories2 = 0
	local score_results = {}
	for i = 1, self.scores[self.current_round] do
		local score1 = self:getScore(self.current_round, first_team_number, i)
		local score2 = self:getScore(self.current_round, first_team_number+1, i)
		if score1 and score2 then 
			if score1 ~= score2 then
				local winner = score1 > score2
				if self.low_winner then winner = not winner end
				if winner then 
					victories1 = victories1 + 1
					score_results[i] = 1
				else 
					victories2 = victories2 + 1
					score_results[i] = 2
				end
			end
		end
		score_results[i] = score_results[i] or 0
	end
	if victories1 == victories2 then return 0, score_results end
	if victories1 > victories2 then return 1, score_results end
	return 2, score_results
end

--[[ ===============================================================================
Disegna la cella per il team.
-- team_name: il nome del team
-- team_numer: il numero del team nella sequenza del round
-- row: la riga della prima cella in cui disegnare il team
-- top: true se è il primo team del match
-- medal: per assegnare la medaglia (1: oro, 2: argento, 0:pari)
-- score_results: risultato degli scores individuali (1: vinto dal primo team, 2 vinto dal secondo, 3 pari)
===============================================================================]]
function TeamBracket:renderTeam(team_name, team_number, row, show_seed, top, medal, score_results, is_bye)

	self:addGap(row, self.current_col, self.current_width, 'rt')
	self:addGap(row+1, self.current_col, self.current_width, 'rt')
	-- seed cell
	if show_seed then
		local seedArg = self:getTeamArg(self.current_round, 'seed', team_number)
		local seedCell = self.rows[row]:tag('td'):attr('rowspan', '2'):cssText(style.seed_cell):wikitext(seedArg):newline()
		if self.not_draw_top then seedCell:css('border-top-width', '0' ) end
		if self.bold_winner and (medal == 1 or medal == 3) then 
			seedCell:cssText(style.winner) 
		end
	end
	-- team cell
	local teamCell = self.rows[row]:tag('td'):attr('rowspan', '2'):cssText(style.team_cell):wikitext(team_name):newline()
	--local teamCell = self.rows[row]:tag('td'):attr('rowspan', '2'):cssText(style.team_cell):wikitext(tostring(seedArg)):newline()
	if not show_seed and (not self.hideSeeds) then
		teamCell:attr('colspan', '2')
	end
	if self.not_draw_top then
		teamCell:css('border-top-width', '0' )
	end
	if self.bold_winner and (medal == 1 or medal == 3) then 
		teamCell:cssText(style.winner) 
	end
	if self.current_round == self.rounds and medal ~= 0 and self.medals then
		if medal == 1 then
			teamCell:cssText(style.first_place)
		elseif medal == 2 then
			teamCell:cssText(style.second_place)
		elseif medal == 3 then
			teamCell:cssText(style.third_place)
		end
	end
	-- scores cells
	for i = 1, self.scores[self.current_round] do
		local scoreCell = self.rows[row]
			:tag('td')
			:attr('rowspan', '2')
			:cssText(style.score_cell)
			:wikitext(self:getScoreArg(self.current_round, team_number, i))
			:newline()
		if self.not_draw_top then scoreCell:css('border-top-width', '0') end
		local pos = (top and 1) or 2
		if score_results[i] == pos then scoreCell:cssText(style.winner) end
	end
	self.not_draw_top = (self.current_round == 1) and (not self.not_draw_top)
end

function TeamBracket:getScore(round, team_number, i)
	local score = string.gsub(self:getScoreArg(round, team_number, i) or '', '%D', '')
	return tonumber(score)
end

--[[ ===============================================================================
Gestisce un match
-- match_number: il numero del match contando dall'alto (1, 2, 3, ...)
-- row_base: la prima riga della tabella in cui disegnare il batch
===============================================================================]]

function TeamBracket:renderMatch(match_number, row_base)

	-- ottiene i nomi dei team del match, verifica che non siano bye e setta self.not_draw_top
	-- per registrare se si deve disegnare o meno la riga superiore del match
	-- ritorna i nomi dei team e se è un bye (true) o no (false)
	local function getTeams(team_number1, team_number2)
		local team_name1 = self:getTeamArg(self.current_round, 'team', team_number1)
		local team_name2 = self:getTeamArg(self.current_round, 'team', team_number2)
		if team_name1 == 'bye' or team_name2 == 'bye' or not (team_name1 and team_name2) then
			self.not_draw_top = false
			return '', '', true
		end
		return team_name1, team_name2, false
	end

	local team_number2 = match_number * 2 
	local team_number1 = team_number2 - 1
	local team_name1, team_name2, is_bye = getTeams(team_number1, team_number2)
	if is_bye then
		if self.render_match[self.current_round][match_number] then
			for r = row_base, row_base+3 do 
				self:addGap(r, self.current_col, self.current_width, 'rm')
			end
			local cell=self.rows[row_base]:tag('td')
				:attr('rowspan', '2')
				:attr('colspan', self.current_width)
				:cssText(style.path_bottom)
			if debug then cell:css('background-color', '#ADD8E6') end
			cell = self.rows[row_base+2]:tag('td')
				:attr('rowspan', '2')
				:attr('colspan', self.current_width)
				:cssText(style.path_top)
			if debug then cell:css('background-color', '#ADD8E6') end
			return row_base
		end
		return nil
	end
	if row_base	< self.min_row_used then self.min_row_used = row_base end
	if row_base + 3 > self.max_row_used then self.max_row_used = row_base + 3 end
	local seedArg1 = self:getTeamArg(self.current_round, 'seed', team_number1)
	local seedArg2 = self:getTeamArg(self.current_round, 'seed', team_number2)
	local showSeed = not self.hideSeeds and (self.showSeeds
		or (seedArg1 and seedArg1 ~= '-')
		or (seedArg2 and seedArg2 ~= '-'))
	local winner, score_results = 0, {}
	if self.bold_winner then 
		winner, score_results = self:getWinner(team_number1)
	end
	local medal2 = (winner == 1 and 2) or (winner == 2 and 1) or 0
	self:renderTeam(team_name1, team_number1, row_base, showSeed, true, winner, score_results, is_bye)
	self:renderTeam(team_name2, team_number2, row_base+2, showSeed, false, medal2, score_results, is_bye)
	return row_base
end

--[[ ===============================================================================
Disegna la finale per il terzo posto
--row: riga in cui iniziare a disegnare la finale
===============================================================================]]

function TeamBracket:render_final_3(row)
	local team_name1 = self:getTeamArg(self.rounds, 'team', 3)
	local team_name2 = self:getTeamArg(self.rounds, 'team', 4)
	if team_name1 == 'bye' or team_name2 == 'bye' then
		return nil
	end
	local seedArg1 = self:getTeamArg(self.rounds, 'seed', 3)
	local seedArg2 = self:getTeamArg(self.rounds, 'seed', 4)
	local showSeed = not self.hideSeeds and (self.showSeeds
		or (seedArg1 and seedArg1 ~= '-')
		or (seedArg2 and seedArg2 ~= '-'))
	local winner, score_results = 0, {}
	if self.bold_winner then 
		winner, score_results = self:getWinner(3)
	end
	self:addGap(row, self.current_col, self.current_width, 'f3')
	if row+4 > self.max_row_used then self.max_row_used = row + 4 end
	self.rows[row]:tag('td')
		:cssText(style.header_third_place)
		:attr('colspan', self.current_width)
		:wikitext(self.args['RD-finalina'] or "Finale 3° posto")
		:newline()
	local medal1 = (winner == 1 and 3) or 0
	local medal2 = (winner == 2 and 3) or 0
	self:renderTeam(team_name1, 3, row+2, showSeed, true, medal1, score_results)
	self:renderTeam(team_name2, 4, row+4, showSeed, false, medal2, score_results)
end

function TeamBracket:AddGroup(row, group_number)
	local name = self.args[string.format('RD%d-group%d', self.current_round, group_number)]
	if name then
		local span =  self.current_col + self.current_width - 2
		self:addGap(row, self.current_col, self.current_col + span, 'g')
		self:addGap(row+1, self.current_col, self.current_col + span, 'g')
		self.rows[row]:tag('td')
			:attr('rowspan', '2')
			:attr('colspan', span)
			:cssText(style.group)
			:wikitext(name)
			:newline()
	end
end

function TeamBracket:renderTree()
	local function normal_gap(row_count, match_number)
		return (row_count + 2 - match_number * 4) / match_number
	end

	local function compact_gap(row_count, match_number)
		return (row_count - 4 * match_number) / match_number
	end

	-- create 3 or 1 rows for every team
	local row_count =  self.teams * 2 + (self.compact and 0 or (self.teams - 2))
	self.min_row_used = row_count
	self.max_row_used = 1
	local gap_function = (self.compact and compact_gap) or normal_gap
	for i = 1, row_count do
		self.rows[i] = mw.html.create('tr')
		self.rows[i]:tag('td'):css('height', style.row_height):wikitext(debug and i or '')
		self.last_element[i] = 1
	end
	self.current_col = 2
	self.render_match = {}
	self.render_match[1] = {}
	for round =1, self.rounds do
		self.current_round = round
		self.render_match[round+1] = {}
		self.current_width = (self.hideSeeds and 1 or 2) + self.scores[round]
		local match_number = math.pow(2, self.rounds - round)
		local gap = gap_function(row_count, match_number)
		local row_base = gap / 2 + (self.compact and 1 or 0)
		local group_number = 1
		for n = 1, match_number, 2 do
			local match1 = self:renderMatch(n, row_base)
			if round < self.rounds then
				local match2 = self:renderMatch(n+1, row_base + gap + 4)
				if not self.compact and round % 4 == 1 then
					self:AddGroup(row_base+4, group_number)
					group_number = group_number + 1
				end
				self:addPath(match1, match2, gap, (n+1)/2)
				row_base = row_base + 2 * gap + 8
			end
		end
		self.current_col = self.current_col + self.current_width + 2
	end
	local third_place = self:getTeamArg(self.rounds, 'team', 3)
	--if true then return third_place end
	if third_place then -- semifinale 3° e 4° posto
		self.current_col = self.current_col - self.current_width - 2
		local offset = gap_function(row_count, 1) / 2 + (self.compact and 1 or 0) + 6
		if offset+5 > row_count then
			for i=row_count+1, offset+5 do
				self.rows[i] = mw.html.create('tr')
				self.rows[i]:tag('td'):css('height', style.row_height):wikitext(debug and i or '')
				self.last_element[i] = 1
			end
		end
		self:render_final_3(offset)
	end
	for row = self.min_row_used, self.max_row_used do
		self.tbl:node(self.rows[row])
	end
end

--[[ ===============================================================================
Disegna le righe di testata del template
===============================================================================]]
function TeamBracket:renderHeading()
	local titleRow = self.tbl:tag('tr')
	local widthRow = self.tbl:tag('tr')
	local blank_text = self.compact and '' or '&nbsp;'
	titleRow:tag('td')
	local row_count = 1
	widthRow:tag('td')
		:css('width', style.buffer_sx_width)
		:css('height', '5px')
		:wikitext(debug and row_count or '')
	row_count = row_count + 1
	for round = 1, self.rounds do
		local colspan = tostring((self.hideSeeds and 1 or 2) + self.scores[round])
		local teamCell = titleRow:tag('td')
			:cssText(style.header_cell)
			:attr('colspan', colspan)
			:wikitext(self:getRoundName(round))
			:newline()
		if not self.hideSeeds then
			widthRow:tag('td'):css('width', style.seed_width):wikitext(debug and row_count or blank_text)
			row_count = row_count + 1
		end
		teamCell = widthRow:tag('td'):css('width', style.team_width):wikitext(debug and row_count or blank_text)
		row_count = row_count + 1
		for i = 1, self.scores[round] do
			widthRow:tag('td'):css('width', style.score_width):wikitext(debug and row_count or blank_text)
			row_count = row_count + 1
		end
		if round < self.rounds then
			titleRow:tag('td'):attr('colspan', '2')
			widthRow:tag('td'):css('width', style.row_width):wikitext(debug and row_count or blank_text)
			row_count = row_count + 1
			widthRow:tag('td'):css('width', style.row_width):wikitext(debug and row_count or blank_text)
			row_count = row_count + 1
		end
	end
end

-- =================================================================
-- Funzione di interfaccia con i template
-- =================================================================

function p.teamBracket(frame)
	local args = getArgs(frame, {
		-- se l'argomento è un seed lo ritorna così com'è anche se blank, tutti gli altri argomenti sono puliti
		valueFunc = function (key, value)
			if not value then return nil end
			if key:find("^RD%d%d?-seed") then return value end
			value = mw.text.trim(value)
			if value == '' then return nil end 
			return value
		end
		}
	)
	if args['debug'] then
		debug = in_array(args['debug'], yes_replies) or debug
	end
	local team_bracket = TeamBracket:new(args)
	return tostring(team_bracket)
end

return p