Модуль:MatchTable
[просмотр] [просмотр кода] [история] [обновить]
Модуль-оболочка для вывода таблиц матчей. Главное назначение — отрисовывать таблицы по указанию мощного модуля TournamentResults, но может генерировать таблички и в чистом виде, если их заполнять вручную, поскольку из-за архитектурных особенностей прямого выхода на базу данных не имеет.
Параметры
Функция group
Рисует таблицы групповых раундов, автоматически подсчитывая количество участвовавших команд и очки.
number_of_rounds =Количество кругов, один или два.compact = yesЕсли параметр задан, то в таблице не отображаются колонки «И», «В», «Н» и «П».team1,team2и т. д. — трёхбуквенные коды участвовавших команд.score1_2— счёт матча с участием указанных команд. Принимает также ссылки вида [[Матч|0:0]], корректно учитывая счёт в результатахbold1,bold2и т. д. — выделение жирным шрифтом нужных команд.color1,color2и т. д. — цвета ячеек указанных команд.
Функция playoff
Более простая функция, поскольку здесь не нужно ничего подсчитывать.
s1_team1 =,s1_team2 =участники первого противостояния.s2_team1 =,s2_team2 =участники второго противостояния.- и т. д.
s1_score =,s2_score =счёт первого матча, счёт второго матча.s2_bold2 =выделение жирным шрифтом нужной команды на нужной строке.s1_color2 =выделение цветом нужной команды на нужной строке.
Функция _rating
Нужна для отрисовывания сворачиваемых таблиц рейтингов мест в группах, но напрямую не вызывается, поскольку для её составления нужен доступ к БД. Является внутренней функцией модуля TournamentResults.
Примеры использования
{{#invoke:MatchTable|playoff
|s1_team1 = ДОМ |s1_team2 = ЧАД |s1_score = 2:1(ET) |s1_color1 = lightgreen |s1_color2 = lightsalmon
|s2_team1 = АБХ |s2_team2 = АВИ |s2_score = [[Финал ЧТМ-2014|5:1]] |s2_color1 = |s2_color2 =
}}
{{#invoke:MatchTable|group
| number_of_rounds = 1
| compact = yes
|team1 = БАГ |color1 = lightgreen | bold1 = yes
|team2 = СКН |color2 = lightsalmon
|team3 = АВИ |color3 = lightsalmon
|team4 = ГАЛ |color4 = lightsalmon
|score1_2 = [[Финал ЧТМ-2014|5:1]]
|score1_3 = 4:0
|score1_4 = 3:2
|score2_3 = 5:1
|score2_4 = 4:1
|score3_4 = 0:0
}}
Пожалуйста, добавляйте категории на страницу документации.
-- =======================================
-- Модуль:MatchTable
-- Оболочка для вывода таблиц матчей
-- =======================================
local p = {}
-- Подключаем базу данных команд
local teamsData = require('Модуль:Data/Teams')
-- Вспомогательная функция: очищает параметр от пробелов.
local function cleanParam(param)
if type(param) == 'string' then
local trimmed = mw.text.trim(param)
if trimmed ~= '' then return trimmed end
elseif param ~= nil then
return param -- Если передали число или boolean из другого модуля
end
return nil
end
-- Вспомогательная функция для парсинга счёта с поддержкой вики-ссылок
local function parse_score(str)
if type(str) ~= 'string' then return nil, nil, false, nil, nil, false, str end
local clean_str = string.gsub(str, "'''", "")
local is_link = false
local is_simple_link = false
local target = nil
local display = clean_str
local m_target, m_display = mw.ustring.match(clean_str, "%[%[([^|]+)|([^%]]+)%]%]")
if m_target then
is_link = true
target = m_target
display = m_display
else
m_target = mw.ustring.match(clean_str, "%[%[([^|%]]+)%]%]")
if m_target then
is_link = true
is_simple_link = true
target = m_target
display = m_target
end
end
local g1, sep, g2 = mw.ustring.match(display, "(%d+)%s*([:%-—–])%s*(%d+)")
if g1 and g2 then
return tonumber(g1), tonumber(g2), is_link, target, sep, is_simple_link, clean_str
end
return nil, nil, false, nil, nil, false, clean_str
end
-- Вспомогательная функция для извлечения аргументов из frame (для #invoke)
local function getArgsFromFrame(frame)
local args = frame:getParent().args
if next(args) == nil then args = frame.args end
return args
end
-- =======================================
-- ПЛЕЙ-ОФФ (Внутренняя функция для Lua)
-- =======================================
function p._playoff(args)
local tbl = mw.html.create('table')
:attr('border', '1')
:attr('cellspacing', '1')
:attr('cellpadding', '1')
:addClass('article-table')
:css('width', '500px')
local row_count = tonumber(cleanParam(args.number_of_strings))
if not row_count then
row_count = 0
while cleanParam(args['s' .. (row_count + 1) .. '_team1']) do
row_count = row_count + 1
end
end
for i = 1, row_count do
local t1_code = cleanParam(args['s' .. i .. '_team1']) or '?'
local t2_code = cleanParam(args['s' .. i .. '_team2']) or '?'
local score = cleanParam(args['s' .. i .. '_score']) or '—'
local color1 = cleanParam(args['s' .. i .. '_color1'])
local color2 = cleanParam(args['s' .. i .. '_color2'])
-- Параметры для жирного шрифта
local bold1_arg = cleanParam(args['s' .. i .. '_bold1'])
local is_bold1 = (bold1_arg == 'yes' or bold1_arg == true)
local bold2_arg = cleanParam(args['s' .. i .. '_bold2'])
local is_bold2 = (bold2_arg == 'yes' or bold2_arg == true)
local t1_name = teamsData.getName(t1_code, 'short')
local t2_name = teamsData.getName(t2_code, 'short')
local tr = tbl:tag('tr')
-- Первая команда: флаг
local td_t1_img = tr:tag('td'):attr('align', 'center'):css('white-space', 'nowrap')
:wikitext(string.format('[[Файл:%s.jpg|50x100px]]', t1_name))
if color1 then td_t1_img:css('background-color', color1) end
-- Первая команда: название
local t1_name_str = string.format('[[%s]]', t1_name)
if is_bold1 then t1_name_str = "'''" .. t1_name_str .. "'''" end
local td_t1_name = tr:tag('td'):attr('align', 'center'):css('white-space', 'nowrap')
:wikitext(t1_name_str)
if color1 then td_t1_name:css('background-color', color1) end
-- Счёт (всегда по центру, без цвета)
tr:tag('td'):attr('align', 'center'):wikitext(tostring(score))
-- Вторая команда: название
local t2_name_str = string.format('[[%s]]', t2_name)
if is_bold2 then t2_name_str = "'''" .. t2_name_str .. "'''" end
local td_t2_name = tr:tag('td'):attr('align', 'center'):css('white-space', 'nowrap')
:wikitext(t2_name_str)
if color2 then td_t2_name:css('background-color', color2) end
-- Вторая команда: флаг
local td_t2_img = tr:tag('td'):attr('align', 'center'):css('white-space', 'nowrap')
:wikitext(string.format('[[Файл:%s.jpg|50x100px]]', t2_name))
if color2 then td_t2_img:css('background-color', color2) end
end
return tostring(tbl)
end
-- Обёртка для вики-кода (Плей-офф)
function p.playoff(frame)
return p._playoff(getArgsFromFrame(frame))
end
-- =======================================
-- ГРУППОВОЙ ЭТАП (Внутренняя функция для Lua)
-- =======================================
function p._group(args)
local rounds = tonumber(cleanParam(args.number_of_rounds)) or 1
local ms_arg = cleanParam(args.manual_sort)
local is_manual = (ms_arg == 'yes' or ms_arg == true)
local compact_arg = cleanParam(args.compact)
local is_compact = (compact_arg == 'yes' or compact_arg == true)
local teams = {}
local n = 0
while cleanParam(args['team' .. (n + 1)]) do
n = n + 1
local code = cleanParam(args['team' .. n])
local name = teamsData.getName(code, 'short')
local color = cleanParam(args['color' .. n])
local bold_arg = cleanParam(args['bold' .. n])
local is_bold = (bold_arg == 'yes' or bold_arg == true)
teams[n] = {
id = n, code = code, name = name, color = color, is_bold = is_bold,
p = 0, w = 0, d = 0, l = 0, gf = 0, ga = 0, pts = 0
}
end
if n == 0 then return "Нет команд для отображения." end
local grid = {}
for i = 1, n do
grid[i] = {}
for j = 1, n do grid[i][j] = {text = "", gf = nil, ga = nil, played = false} end
end
for i = 1, n do
for j = 1, n do
if i ~= j and not grid[i][j].played then
local s_ij = cleanParam(args['score' .. i .. '_' .. j])
local s_ji = cleanParam(args['score' .. j .. '_' .. i])
if s_ij then
local g1, g2, is_link, target, sep, is_simple_link, clean_str = parse_score(s_ij)
if g1 then
local text_ij = is_link and ("'''" .. clean_str .. "'''") or clean_str
grid[i][j] = {text = text_ij, gf = g1, ga = g2, played = true}
if rounds == 1 then
local mirrored_score = g2 .. sep .. g1
local text_ji = ""
if is_link then
if is_simple_link then
text_ji = "'''[[" .. mirrored_score .. "]]'''"
else
text_ji = "'''[[" .. target .. "|" .. mirrored_score .. "]]'''"
end
else
text_ji = mirrored_score
end
grid[j][i] = {text = text_ji, gf = g2, ga = g1, played = true}
end
else
grid[i][j] = {text = s_ij, gf = nil, ga = nil, played = false}
end
elseif rounds == 1 and s_ji then
local g1, g2, is_link, target, sep, is_simple_link, clean_str = parse_score(s_ji)
if g1 then
local mirrored_score = g2 .. sep .. g1
local text_ij = ""
if is_link then
if is_simple_link then
text_ij = "'''[[" .. mirrored_score .. "]]'''"
else
text_ij = "'''[[" .. target .. "|" .. mirrored_score .. "]]'''"
end
else
text_ij = mirrored_score
end
grid[i][j] = {text = text_ij, gf = g2, ga = g1, played = true}
local text_ji = is_link and ("'''" .. clean_str .. "'''") or clean_str
grid[j][i] = {text = text_ji, gf = g1, ga = g2, played = true}
end
end
end
end
end
for i = 1, n do
for j = 1, n do
if i ~= j and grid[i][j].played then
local gf, ga = grid[i][j].gf, grid[i][j].ga
teams[i].p = teams[i].p + 1
teams[i].gf = teams[i].gf + gf
teams[i].ga = teams[i].ga + ga
if gf > ga then
teams[i].w = teams[i].w + 1
teams[i].pts = teams[i].pts + 3
elseif gf == ga then
teams[i].d = teams[i].d + 1
teams[i].pts = teams[i].pts + 1
else
teams[i].l = teams[i].l + 1
end
end
end
end
local sorted_teams = {}
for i = 1, n do table.insert(sorted_teams, teams[i]) end
if not is_manual then
local function get_h2h_stats(t_ids)
local h2h = {}
for _, id in ipairs(t_ids) do h2h[id] = {pts = 0, gd = 0, gf = 0} end
for i = 1, #t_ids do
for j = 1, #t_ids do
local id1, id2 = t_ids[i], t_ids[j]
if id1 ~= id2 and grid[id1][id2].played then
local g1, g2 = grid[id1][id2].gf, grid[id1][id2].ga
h2h[id1].gf = h2h[id1].gf + g1
h2h[id1].gd = h2h[id1].gd + (g1 - g2)
if g1 > g2 then h2h[id1].pts = h2h[id1].pts + 3
elseif g1 == g2 then h2h[id1].pts = h2h[id1].pts + 1
end
end
end
end
return h2h
end
table.sort(sorted_teams, function(a, b)
if a.pts ~= b.pts then return a.pts > b.pts end
if (a.gf - a.ga) ~= (b.gf - b.ga) then return (a.gf - a.ga) > (b.gf - b.ga) end
if a.gf ~= b.gf then return a.gf > b.gf end
return a.id < b.id
end)
local i = 1
while i <= n do
local j = i
while j < n and
sorted_teams[j+1].pts == sorted_teams[i].pts and
(sorted_teams[j+1].gf - sorted_teams[j+1].ga) == (sorted_teams[i].gf - sorted_teams[i].ga) and
sorted_teams[j+1].gf == sorted_teams[i].gf do
j = j + 1
end
if j > i then
local tied_ids = {}
for k = i, j do table.insert(tied_ids, sorted_teams[k].id) end
local h2h = get_h2h_stats(tied_ids)
local sub = {}
for k = i, j do table.insert(sub, sorted_teams[k]) end
table.sort(sub, function(a, b)
if h2h[a.id].pts ~= h2h[b.id].pts then return h2h[a.id].pts > h2h[b.id].pts end
if h2h[a.id].gd ~= h2h[b.id].gd then return h2h[a.id].gd > h2h[b.id].gd end
if h2h[a.id].gf ~= h2h[b.id].gf then return h2h[a.id].gf > h2h[b.id].gf end
return a.id < b.id
end)
for k = i, j do sorted_teams[k] = sub[k - i + 1] end
end
i = j + 1
end
end
local tbl = mw.html.create('table')
:attr('border', '1')
:attr('cellspacing', '1')
:attr('cellpadding', '1')
:addClass('article-table')
:css('width', '500px')
local tr_head = tbl:tag('tr')
tr_head:tag('th'):attr('scope', 'col'):wikitext('Место')
tr_head:tag('th'):attr('scope', 'col'):wikitext('')
tr_head:tag('th'):attr('scope', 'col'):wikitext('Команда')
for i = 1, n do tr_head:tag('th'):attr('scope', 'col'):wikitext(tostring(i)) end
if not is_compact then
tr_head:tag('th'):attr('scope', 'col'):attr('title', 'Игры'):wikitext('И')
tr_head:tag('th'):attr('scope', 'col'):attr('title', 'Выигрыши'):wikitext('В')
tr_head:tag('th'):attr('scope', 'col'):attr('title', 'Ничьи'):wikitext('Н')
tr_head:tag('th'):attr('scope', 'col'):attr('title', 'Поражения'):wikitext('П')
end
tr_head:tag('th'):attr('scope', 'col'):attr('title', 'Забитые и пропущенные мячи'):wikitext('М')
tr_head:tag('th'):attr('scope', 'col'):attr('title', 'Очки'):wikitext('О')
for rank, t in ipairs(sorted_teams) do
local r = tbl:tag('tr')
local rank_str = tostring(rank)
if t.is_bold then rank_str = "'''" .. rank_str .. "'''" end
local td_rank = r:tag('td'):attr('align', 'center'):css('white-space', 'nowrap'):wikitext(rank_str)
if t.color then td_rank:css('background-color', t.color) end
local td_flag = r:tag('td'):attr('align', 'center'):css('white-space', 'nowrap')
:wikitext(string.format('[[Файл:%s.jpg|50x100px]]', t.name))
if t.color then td_flag:css('background-color', t.color) end
local name_str = string.format('[[%s]]', t.name)
if t.is_bold then name_str = "'''" .. name_str .. "'''" end
local td_name = r:tag('td'):attr('align', 'center'):css('white-space', 'nowrap'):wikitext(name_str)
if t.color then td_name:css('background-color', t.color) end
for j = 1, n do
local opp = sorted_teams[j]
local td_match = r:tag('td'):attr('align', 'center')
if t.id == opp.id then
td_match:css('background-color', 'grey')
else
local m = grid[t.id][opp.id]
if m.played or m.text ~= "" then td_match:wikitext(m.text) end
end
end
if not is_compact then
r:tag('td'):attr('align', 'center'):wikitext(tostring(t.p))
r:tag('td'):attr('align', 'center'):wikitext(tostring(t.w))
r:tag('td'):attr('align', 'center'):wikitext(tostring(t.d))
r:tag('td'):attr('align', 'center'):wikitext(tostring(t.l))
end
r:tag('td'):attr('align', 'center'):css('white-space', 'nowrap'):wikitext(string.format('%d-%d', t.gf, t.ga))
r:tag('td'):attr('align', 'center'):tag('b'):wikitext(tostring(t.pts))
end
return tostring(tbl)
end
-- Обёртка для вики-кода (Группы)
function p.group(frame)
return p._group(getArgsFromFrame(frame))
end
return p