Модуль:TournamentResults: различия между версиями

Материал из ЧТМ
Перейти к навигации Перейти к поиску
Нет описания правки
Нет описания правки
Строка 5: Строка 5:
local p = {}
local p = {}


-- Подключаем наш отрисовщик таблиц
local matchTable = require('Модуль:MatchTable')
local matchTable = require('Модуль:MatchTable')


-- Словарь цветов и жирности
local COLORS = {
local COLORS = {
     ["G"] = { c = "lightgreen", b = true },
     ["G"] = { c = "lightgreen", b = true },
Строка 16: Строка 14:
}
}


-- Функция для очистки параметров
local function cleanParam(param)
local function cleanParam(param)
     if type(param) == 'string' then
     if type(param) == 'string' then
Строка 27: Строка 24:
end
end


-- =======================================
-- ОСНОВНАЯ ФУНКЦИЯ СБОРКИ (Для #invoke)
-- =======================================
function p.build(frame)
function p.build(frame)
     local args = frame:getParent().args
     local args = frame:getParent().args
Строка 38: Строка 32:


     if not year or not tournament then
     if not year or not tournament then
         return '<strong class="error">Ошибка: Не указаны обязательные параметры year и/или tournament.</strong>'
         return '<strong class="error">Ошибка: Не указаны параметры year и/или tournament.</strong>'
     end
     end


    -- 1. ЗАГРУЗКА БАЗЫ ДАННЫХ
     local success, full_db = pcall(mw.loadData, 'Модуль:Data/Tournaments/' .. year)
     local success, full_db = pcall(mw.loadData, 'Модуль:Data/Tournaments/' .. year)
     if not success then
     if not success then
         return '<strong class="error">Ошибка: Не удалось загрузить базу данных за ' .. year .. ' год.</strong>'
         return '<strong class="error">Ошибка: Не удалось загрузить БД за ' .. year .. ' год.</strong>'
     end
     end


     local tour_data = full_db[tournament]
     local tour_data = full_db[tournament]
     if not tour_data then
     if not tour_data then
         return '<strong class="error">Ошибка: Турнир "' .. tournament .. '" не найден в базе ' .. year .. ' года.</strong>'
         return '<strong class="error">Ошибка: Турнир "' .. tournament .. '" не найден.</strong>'
     end
     end


     local output = {}
     local output = {}


    -- 2. ЦИКЛ ПО БЛОКАМ СТРАНИЦЫ
     for i = 1, 50 do
     for i = 1, 50 do
         local title_type = cleanParam(args['title_type' .. i])
         local title_type = cleanParam(args['title_type' .. i])
Строка 64: Строка 56:
         local rating = cleanParam(args['rating' .. i])
         local rating = cleanParam(args['rating' .. i])


        -- Условие выхода из цикла
         if not (title or text or table_id or rating) then break end
         if not (title or text or table_id or rating) then
            break
        end


         -- --- А. Заголовок ---
         -- Заголовки и текст
         if title then
         if title then
             if title_type == "0" or title_type == "7" then
             if title_type == "0" or title_type == "7" then
Строка 80: Строка 69:
         end
         end


        -- --- Б. Текст ---
         if text then table.insert(output, text) end
         if text then
         if rating then table.insert(output, "''Здесь будет таблица рейтинга: " .. rating .. "''") end
            table.insert(output, text)
         end


         -- --- В. Отрисовка рейтинга ---
         -- Таблицы
        if rating then
            table.insert(output, "''Здесь будет таблица рейтинга: " .. rating .. "''")
        end
 
        -- --- Г. Таблицы ---
         if table_id then
         if table_id then
             local db_node = tour_data[table_id]
             local db_node = tour_data[table_id]
Строка 99: Строка 81:
                 local t_args = {}
                 local t_args = {}
                  
                  
                -- =====================
                 -- ОБРАБОТКА ГРУППЫ
                 -- ОБРАБОТКА ГРУППЫ
                -- =====================
                 if db_node.type == "group" then
                 if db_node.type == "group" then
                     t_args.number_of_rounds = db_node.number_of_rounds or 1
                     t_args.number_of_rounds = db_node.number_of_rounds or 1
Строка 107: Строка 87:
                      
                      
                     local team_map = {}
                     local team_map = {}
                   
                     for idx, st in ipairs(db_node.standings) do
                     for idx, st in ipairs(db_node.standings) do
                         local code = st[1]
                         local code = st[1]
                         local color_code = st[2]
                         local color_code = st[2]
                       
                         team_map[code] = idx
                         team_map[code] = idx
                         t_args['team' .. idx] = code
                         t_args['team' .. idx] = code
                          
                          
                         local style = COLORS[color_code]
                         if COLORS[color_code] then
                        if style then
                             t_args['color' .. idx] = COLORS[color_code].c
                             t_args['color' .. idx] = style.c
                             if COLORS[color_code].b then t_args['bold' .. idx] = "yes" end
                             if style.b then t_args['bold' .. idx] = "yes" end
                         end
                         end
                     end
                     end
Строка 125: Строка 102:
                         local id_home = team_map[m[1]]
                         local id_home = team_map[m[1]]
                         local id_away = team_map[m[2]]
                         local id_away = team_map[m[2]]
                       
                         if id_home and id_away and m[3] ~= nil and m[4] ~= nil then
                         if id_home and id_away then
                            local score_str = tostring(m[3]) .. ":" .. tostring(m[4])
                            local g1 = m[3]
                            local link_val = cleanParam(args['link' .. i .. '_' .. id_home .. '_' .. id_away])
                            local g2 = m[4]
                            if link_val then score_str = "[[" .. link_val .. "|" .. score_str .. "]]" end
                           
                            t_args['score' .. id_home .. '_' .. id_away] = score_str
                            if g1 ~= nil and g2 ~= nil then
                                local score_str = tostring(g1) .. ":" .. tostring(g2)
                               
                                local link_val = cleanParam(args['link' .. i .. '_' .. id_home .. '_' .. id_away])
                                if link_val then
                                    score_str = "[[" .. link_val .. "|" .. score_str .. "]]"
                                end
                               
                                t_args['score' .. id_home .. '_' .. id_away] = score_str
                            end
                         end
                         end
                     end
                     end
                      
                      
                     local ok, rendered = pcall(matchTable._group, t_args)
                     local ok, rendered = pcall(matchTable._group, t_args)
                     if ok then
                     if ok then table.insert(output, rendered) else table.insert(output, '<strong class="error">Сбой групп: ' .. tostring(rendered) .. '</strong>') end
                        table.insert(output, rendered)
                    else
                        table.insert(output, '<strong class="error">Сбой в MatchTable._group: ' .. tostring(rendered) .. '</strong>')
                    end


                -- =====================
                 -- ОБРАБОТКА ПЛЕЙ-ОФФ
                 -- ОБРАБОТКА ПЛЕЙ-ОФФ
                -- =====================
                 elseif db_node.type == "knockout" or db_node.type == "playoff" then
                 elseif db_node.type == "knockout" or db_node.type == "playoff" then
                    -- Надежно передаем количество строк текстом
                     t_args.number_of_strings = tostring(#db_node.matches)
                     t_args.number_of_strings = tostring(#db_node.matches)
                      
                      
                     for k, m in ipairs(db_node.matches) do
                     for k, m in ipairs(db_node.matches) do
                        -- Извлекаем значения жестко по индексам (nil нам не страшны)
                         local t1, t2, g1, g2, flag, p1, p2, c_code1, c_code2 = m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9]
                         local t1 = m[1]
                        local t2 = m[2]
                        local g1 = m[3]
                        local g2 = m[4]
                        local flag = m[5]
                        local p1 = m[6]
                        local p2 = m[7]
                        local c_code1 = m[8]
                        local c_code2 = m[9]
                          
                          
                         t_args['s' .. k .. '_team1'] = t1
                         t_args['s' .. k .. '_team1'] = t1
Строка 173: Строка 124:
                          
                          
                         local score_str = "—"
                         local score_str = "—"
                       
                        -- Проверка на сыгранный матч
                         if g1 ~= nil and g2 ~= nil then
                         if g1 ~= nil and g2 ~= nil then
                             score_str = tostring(g1) .. ":" .. tostring(g2)
                             score_str = tostring(g1) .. ":" .. tostring(g2)
                           
                             if flag == "aet" then score_str = score_str .. "(ET)"
                             if flag == "aet" then
                             elseif flag == "pen" then score_str = score_str .. "(пен." .. tostring(p1) .. ":" .. tostring(p2) .. ")" end
                                score_str = score_str .. "(ET)"
                             elseif flag == "pen" then
                                score_str = score_str .. "(пен." .. tostring(p1) .. ":" .. tostring(p2) .. ")"
                            end
                         end
                         end
                          
                          
                        -- Обработка ссылки
                         local link_val = cleanParam(args['link' .. i .. '_' .. k]) or (k == 1 and cleanParam(args['link' .. i]))
                         local link_val = cleanParam(args['link' .. i .. '_' .. k]) or (k == 1 and cleanParam(args['link' .. i]))
                         if link_val and score_str ~= "—" then
                         if link_val and score_str ~= "—" then score_str = "[[" .. link_val .. "|" .. score_str .. "]]" end
                            score_str = "[[" .. link_val .. "|" .. score_str .. "]]"
                        end
                          
                          
                         t_args['s' .. k .. '_score'] = score_str
                         t_args['s' .. k .. '_score'] = score_str
                          
                          
                        -- Цвета и жирность (передаем текстом "yes")
                         if c_code1 and COLORS[c_code1] then
                         if c_code1 and COLORS[c_code1] then
                            local style1 = COLORS[c_code1]
                             t_args['s' .. k .. '_color1'] = COLORS[c_code1].c
                             t_args['s' .. k .. '_color1'] = style1.c
                             if COLORS[c_code1].b then t_args['s' .. k .. '_bold1'] = "yes" end
                             if style1.b then t_args['s' .. k .. '_bold1'] = "yes" end
                         end
                         end
                          
                          
                         if c_code2 and COLORS[c_code2] then
                         if c_code2 and COLORS[c_code2] then
                            local style2 = COLORS[c_code2]
                             t_args['s' .. k .. '_color2'] = COLORS[c_code2].c
                             t_args['s' .. k .. '_color2'] = style2.c
                             if COLORS[c_code2].b then t_args['s' .. k .. '_bold2'] = "yes" end
                             if style2.b then t_args['s' .. k .. '_bold2'] = "yes" end
                         end
                         end
                     end
                     end
                      
                      
                    -- Защищенный вызов отрисовщика
                     local ok, rendered = pcall(matchTable._playoff, t_args)
                     local ok, rendered = pcall(matchTable._playoff, t_args)
                     if ok then
                     if not ok then
                         if rendered == nil or rendered == "" then
                         table.insert(output, '<strong class="error">Сбой pcall: ' .. tostring(rendered) .. '</strong>')
                            table.insert(output, '<strong class="error">Ошибка: Модуль MatchTable._playoff вернул пустую строку. Проверьте правильность параметров.</strong>')
                    elseif not rendered or rendered == "" then
                         else
                        table.insert(output, '<strong class="error">MatchTable вернул пустую строку.</strong>')
                            table.insert(output, rendered)
                    elseif not string.find(rendered, "<tr") then
                         end
                        -- АВАРИЙНАЯ ОТЛАДКА: Если таблица сгенерировалась без строк
                         local dbg = {}
                        for dk, dv in pairs(t_args) do table.insert(dbg, dk .. " = " .. tostring(dv)) end
                        table.sort(dbg)
                         table.insert(output, '<div style="border:2px solid red; padding:10px; margin:10px 0;">' ..
                            '<b style="color:red;">Таблица плей-офф пуста! Аргументы, переданные в MatchTable:</b><br/>' ..
                            table.concat(dbg, "<br/>") .. '</div>')
                     else
                     else
                         table.insert(output, '<strong class="error">Критический сбой внутри MatchTable._playoff: ' .. tostring(rendered) .. '</strong>')
                         table.insert(output, rendered)
                     end
                     end
               
                else
                    table.insert(output, '<strong class="error">Ошибка: Неизвестный тип таблицы "' .. tostring(db_node.type) .. '".</strong>')
                 end
                 end
             end
             end
         end
         end


        -- --- Д. Примечание ---
         if ref then table.insert(output, "<small>" .. ref .. "</small>") end
         if ref then
            table.insert(output, "<small>" .. ref .. "</small>")
        end
 
         table.insert(output, "")  
         table.insert(output, "")  
     end
     end

Версия от 13:17, 22 апреля 2026

Документация Документация

Модуль для вывода полных результатов турниров в нужном формате. За один проход по базе данных вытаскивает оттуда все требуемые результаты, подсчитывает нужные показатели и выдаёт сырую информацию модулю MatchTable, который рисует нужные таблицы.

Параметры

Общие

  • year — год турнира.
  • tournament — название турнира, массив из базы данных, например, ["ЧТМ_2046_Qual"] (без [""]).

Строковые

С обязательной цифрой-номером строки.

Общие

  • title_type1 — числовой параметр. Уровень заголовка, то есть количество знаков равенства в вики-разметке от 2 до 6, если 0, то выдаётся псевдо-заголовок Такого вида.
  • title1 — сам заголовок, то, что в нём будет написано.
  • text1 (опционально) — текст между заголовком и таблицей, поддерживает вики-разметку и переносы строк.
  • table1 — таблица, заполняется кодом массива из базы данных конкретного турнира, например, ["1R_GroupA"] (без [""]).
  • ref1 (опционально) — примечание мелким шрифтом под таблицей.

Частные

Эти параметры зависят от типа таблицы, которую вы хотите вывести в конкретной строке — таблицу группы или рейтинга. Для таблицы плей-офф особых параметров нет.

Группа
  • compact1 — если задано yes, то в таблице не показываются колонки «И», «В», «Н» и «П».
  • tiebreaker1 — в случае полного равенства команд необходимо расставить их вручную, указав через запятую трёхбуквенные коды.
  • places1 — если нужно расставить места не так, как подсчитано автоматически, то можно расставить вручную, указав через запятую трёхбуквенные коды.
Рейтинг
  • rating_title1 — название сворачиваемой таблицы, как правило, «Рейтинг вторых мест» или «Рейтинг третьих мест».
  • rating1 — префикс раунда из базы данных, рейтинг мест в котором вы хотите подсчитать, как правило 1R, 2R или 3R.
  • rating_place1 — числовой параметр, номер мест, чей рейтинг вы хотите подсчитать, как правило 2 или 3. Если задано last, то считается рейтинг последних мест.
  • rating_colors1 — цветовое оформление строк таблицы, указывайте количество строк и цвета. Например, 2:G, 2:Y, 8:L, 2:R, читается как «2 зелёных, 2 жёлтых, 8 светло-жёлтых, 2 красных». Строка rating_colors полностью игнорирует пробелы, запятые и тире, она ищет только паттерны Число:Буква. Можно писать 2:G, 4:Y, 2:G 4:Y — всё поймёт без проблем. Буквы цветов те же, что и в базе:
    • G{{{3}}} (lightgreen)
    • Y{{{3}}} (palegoldenrod)
    • L{{{3}}} (lightyellow)
    • R{{{3}}} (lightsalmon)
    • 0{{{3}}} (без раскраски)
  • rating_tiebreaker1 — в случае полного равенства команд необходимо расставить их вручную, указав через запятую трёхбуквенные коды.
  • places1 — если нужно расставить места не так, как подсчитано автоматически, то можно расставить вручную, указав через запятую трёхбуквенные коды.

Заготовки для копирования

Обёртка
{{#invoke:TournamentResults|build
|year = 
|tournament = 
}}
Заголовки без таблиц
|title_type=|title=|text=
Таблицы групп
|title_type=|title=|table=|compact=yes
Таблицы плей-офф
|title_type=|title=|table=
Таблицы рейтинга
|rating_title=|rating=|rating_place=|rating_colors=

Пожалуйста, добавляйте категории на страницу документации.

-- =======================================
-- Модуль:TournamentResults
-- Сборщик турнирных страниц из БД
-- =======================================
local p = {}

local matchTable = require('Модуль:MatchTable')

local COLORS = {
    ["G"] = { c = "lightgreen", b = true },
    ["Y"] = { c = "palegoldenrod", b = false },
    ["L"] = { c = "lightyellow", b = false },
    ["R"] = { c = "lightsalmon", b = false }
}

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
    end
    return nil
end

function p.build(frame)
    local args = frame:getParent().args
    if next(args) == nil then args = frame.args end

    local year = cleanParam(args.year)
    local tournament = cleanParam(args.tournament)

    if not year or not tournament then
        return '<strong class="error">Ошибка: Не указаны параметры year и/или tournament.</strong>'
    end

    local success, full_db = pcall(mw.loadData, 'Модуль:Data/Tournaments/' .. year)
    if not success then
        return '<strong class="error">Ошибка: Не удалось загрузить БД за ' .. year .. ' год.</strong>'
    end

    local tour_data = full_db[tournament]
    if not tour_data then
        return '<strong class="error">Ошибка: Турнир "' .. tournament .. '" не найден.</strong>'
    end

    local output = {}

    for i = 1, 50 do
        local title_type = cleanParam(args['title_type' .. i])
        local title = cleanParam(args['title' .. i])
        local text = cleanParam(args['text' .. i])
        local table_id = cleanParam(args['table' .. i])
        local ref = cleanParam(args['ref' .. i])
        local compact = cleanParam(args['compact' .. i])
        local rating = cleanParam(args['rating' .. i])

        if not (title or text or table_id or rating) then break end

        -- Заголовки и текст
        if title then
            if title_type == "0" or title_type == "7" then
                table.insert(output, "; " .. title)
            else
                local level = tonumber(title_type) or 2
                local eq = string.rep("=", level)
                table.insert(output, eq .. " " .. title .. " " .. eq)
            end
        end

        if text then table.insert(output, text) end
        if rating then table.insert(output, "''Здесь будет таблица рейтинга: " .. rating .. "''") end

        -- Таблицы
        if table_id then
            local db_node = tour_data[table_id]
            
            if not db_node then
                table.insert(output, '<strong class="error">Ошибка: Массив ' .. table_id .. ' не найден в БД.</strong>')
            else
                local t_args = {}
                
                -- ОБРАБОТКА ГРУППЫ
                if db_node.type == "group" then
                    t_args.number_of_rounds = db_node.number_of_rounds or 1
                    t_args.compact = (compact == "yes" or compact == "true")
                    
                    local team_map = {}
                    for idx, st in ipairs(db_node.standings) do
                        local code = st[1]
                        local color_code = st[2]
                        team_map[code] = idx
                        t_args['team' .. idx] = code
                        
                        if COLORS[color_code] then
                            t_args['color' .. idx] = COLORS[color_code].c
                            if COLORS[color_code].b then t_args['bold' .. idx] = "yes" end
                        end
                    end
                    
                    for _, m in ipairs(db_node.matches) do
                        local id_home = team_map[m[1]]
                        local id_away = team_map[m[2]]
                        if id_home and id_away and m[3] ~= nil and m[4] ~= nil then
                            local score_str = tostring(m[3]) .. ":" .. tostring(m[4])
                            local link_val = cleanParam(args['link' .. i .. '_' .. id_home .. '_' .. id_away])
                            if link_val then score_str = "[[" .. link_val .. "|" .. score_str .. "]]" end
                            t_args['score' .. id_home .. '_' .. id_away] = score_str
                        end
                    end
                    
                    local ok, rendered = pcall(matchTable._group, t_args)
                    if ok then table.insert(output, rendered) else table.insert(output, '<strong class="error">Сбой групп: ' .. tostring(rendered) .. '</strong>') end

                -- ОБРАБОТКА ПЛЕЙ-ОФФ
                elseif db_node.type == "knockout" or db_node.type == "playoff" then
                    t_args.number_of_strings = tostring(#db_node.matches)
                    
                    for k, m in ipairs(db_node.matches) do
                        local t1, t2, g1, g2, flag, p1, p2, c_code1, c_code2 = m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9]
                        
                        t_args['s' .. k .. '_team1'] = t1
                        t_args['s' .. k .. '_team2'] = t2
                        
                        local score_str = "—"
                        if g1 ~= nil and g2 ~= nil then
                            score_str = tostring(g1) .. ":" .. tostring(g2)
                            if flag == "aet" then score_str = score_str .. "(ET)"
                            elseif flag == "pen" then score_str = score_str .. "(пен." .. tostring(p1) .. ":" .. tostring(p2) .. ")" end
                        end
                        
                        local link_val = cleanParam(args['link' .. i .. '_' .. k]) or (k == 1 and cleanParam(args['link' .. i]))
                        if link_val and score_str ~= "—" then score_str = "[[" .. link_val .. "|" .. score_str .. "]]" end
                        
                        t_args['s' .. k .. '_score'] = score_str
                        
                        if c_code1 and COLORS[c_code1] then
                            t_args['s' .. k .. '_color1'] = COLORS[c_code1].c
                            if COLORS[c_code1].b then t_args['s' .. k .. '_bold1'] = "yes" end
                        end
                        
                        if c_code2 and COLORS[c_code2] then
                            t_args['s' .. k .. '_color2'] = COLORS[c_code2].c
                            if COLORS[c_code2].b then t_args['s' .. k .. '_bold2'] = "yes" end
                        end
                    end
                    
                    local ok, rendered = pcall(matchTable._playoff, t_args)
                    if not ok then
                        table.insert(output, '<strong class="error">Сбой pcall: ' .. tostring(rendered) .. '</strong>')
                    elseif not rendered or rendered == "" then
                        table.insert(output, '<strong class="error">MatchTable вернул пустую строку.</strong>')
                    elseif not string.find(rendered, "<tr") then
                        -- АВАРИЙНАЯ ОТЛАДКА: Если таблица сгенерировалась без строк
                        local dbg = {}
                        for dk, dv in pairs(t_args) do table.insert(dbg, dk .. " = " .. tostring(dv)) end
                        table.sort(dbg)
                        table.insert(output, '<div style="border:2px solid red; padding:10px; margin:10px 0;">' ..
                            '<b style="color:red;">Таблица плей-офф пуста! Аргументы, переданные в MatchTable:</b><br/>' .. 
                            table.concat(dbg, "<br/>") .. '</div>')
                    else
                        table.insert(output, rendered)
                    end
                end
            end
        end

        if ref then table.insert(output, "<small>" .. ref .. "</small>") end
        table.insert(output, "") 
    end

    return table.concat(output, "\n")
end

return p