Модуль:Участники финального турнира: различия между версиями

Материал из ЧТМ
Перейти к навигации Перейти к поиску
никаких полных названий
исправление
 
Строка 192: Строка 192:
                 -- Ссылка на команду
                 -- Ссылка на команду
                 local link = (team.full == team.short) and string.format('[[%s]]', team.short)  
                 local link = (team.full == team.short) and string.format('[[%s]]', team.short)  
                             or string.format('[%s]]', team.short)
                             or string.format('[[%s]]', team.short)
                              
                              
                 tr:tag('td')
                 tr:tag('td')

Текущая версия от 20:35, 1 июня 2026

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

Модуль для автоматического формирования таблицы участников финального турнира. Может работать как в полностью автоматическом, так и в полуавтоматическом режиме.

Полностью автоматический режим

{{#invoke:TournamentParticipants|main|prefix=Код_турнира|year=Год}}

Или просто:

{{#invoke:TournamentParticipants|main|Код_турнира|Год}}

Например:

{{#invoke:TournamentParticipants|main|prefix=ЧТМ|year=2046}}

или:

{{#invoke:TournamentParticipants|main|ЧТМ|2046}}

Оба варианта идентичны. Модуль сам найдёт всех участников и подсчитает для каждого общее количество участий в финальном турнире.

Полуавтоматический режим

{{#invoke:TournamentParticipants|main|prefix=Код_турнира|year=Год|teams=Список через запятую}}

Или просто:

{{#invoke:TournamentParticipants|main|Код_турнира|Год|Список через запятую}}

Этот вариант можно применять в тех случаях, когда квалификация уже состоялась, а финальный турнир ещё не стартовал и массива для него в БД в принципе нет.

Например:

{{#invoke:TournamentParticipants|main|prefix=ЧТМ|year=2046|teams=ДОМ, МОН, КИР, ИНД, СЕН, ТЕР}}

или:

{{#invoke:TournamentParticipants|main|ЧТМ|2046|ДОМ, МОН, КИР, ИНД, СЕН, ТЕР}}


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

local p = {}

-- Подключаем базу команд
local teams_module = require("Модуль:Data/Teams")

-- Список годов, которые по структуре БД точно не существуют
local SKIP_YEARS = {
    [2007] = true,
    [2008] = true,
    [2011] = true,
    [2012] = true,
    [2016] = true
}

-- Вспомогательная функция: вытаскивает все уникальные команды из таблицы турнира
local function extract_teams(tournament_data)
    local teams_set = {}
    for _, stage_data in pairs(tournament_data) do
        if stage_data.type == "group" and stage_data.standings then
            for _, row in ipairs(stage_data.standings) do
                teams_set[row[1]] = true
            end
        elseif stage_data.type == "knockout" and stage_data.matches then
            for _, row in ipairs(stage_data.matches) do
                teams_set[row[1]] = true
                teams_set[row[2]] = true
            end
        end
    end
    return teams_set
end

-- Вспомогательная функция: ищет победителя турнира (действующего чемпиона)
local function get_champion(tournament_data)
    for stage_name, stage_data in pairs(tournament_data) do
        -- Ищем финал (отсекаем четверть- и полуфиналы)
        if stage_name:match("Final$") and not stage_name:match("Semifinal$") and not stage_name:match("Quarterfinal$") then
            if stage_data.matches and stage_data.matches[1] then
                local m = stage_data.matches[1]
                local t1, t2 = m[1], m[2]
                local c1, c2
                
                -- Индексы ячеек цвета зависят от количества раундов
                if stage_data.number_of_rounds == 2 then
                    c1, c2 = m[10], m[11]
                else
                    c1, c2 = m[8], m[9]
                end
                
                -- Оптимизация: определяем победителя по зелёному цвету ячейки ("G")
                if c1 == "G" then return t1 end
                if c2 == "G" then return t2 end
            end
        end
    end
    return nil
end

function p.main(frame)
    local args = frame.args[1] and frame.args or frame:getParent().args
    
    local prefix = args[1] or args.prefix
    local target_year = tonumber(args[2] or args.year)
    local manual_teams = args[3] or args.teams -- Новый параметр для ручного списка
    
    if not prefix or not target_year then
        return '<strong class="error">Ошибка: не указан префикс турнира или год.</strong>'
    end

    local target_tournament = prefix .. "_" .. target_year .. "_Final"
    
    -- Хранилища для данных
    local participants = {} 
    local appearances = {}  
    local champion_code = nil
    local champion_found = false
    local manual_mode = false

    -- === ОБРАБОТКА РУЧНОГО СПИСКА (ЕСЛИ ЕСТЬ) ===
    if manual_teams and manual_teams ~= "" then
        manual_mode = true
        -- Разбиваем список по запятой
        for item in mw.text.gsplit(manual_teams, ",") do
            local team_input = mw.text.trim(item)
            if team_input ~= "" then
                local code = mw.ustring.upper(team_input)
                
                -- Проверяем, ввёл ли юзер код или название. Если название — получаем код.
                if not teams_module.getTeam(code) then
                    local resolved_code = teams_module.getCode(team_input)
                    if resolved_code then code = resolved_code end
                end
                
                participants[code] = true
                appearances[code] = 1 -- Засчитываем участие в будущем турнире
            end
        end
    end

    -- Если список задан вручную, начинаем сканировать БД с прошлого года
    local start_year = manual_mode and (target_year - 1) or target_year

    -- === 1 ПРОХОД ПО БАЗАМ ДАННЫХ ===
    for y = start_year, 2006, -1 do
        if not SKIP_YEARS[y] then
            local success, year_db = pcall(require, "Модуль:Data/Tournaments/" .. y)
            
            if success and year_db then
                local t_data = year_db[prefix .. "_" .. y .. "_Final"]
                
                if t_data then
                    local unique_teams = extract_teams(t_data)
                    
                    if not manual_mode and y == target_year then
                        -- Работаем в автоматическом режиме: фиксируем состав участников целевого турнира
                        for code in pairs(unique_teams) do
                            participants[code] = true
                            appearances[code] = 1 
                        end
                    else
                        -- Считаем прошлые участия ТОЛЬКО для команд-участниц заданного года
                        for code in pairs(unique_teams) do
                            if participants[code] then
                                appearances[code] = appearances[code] + 1
                            end
                        end
                        
                        -- Ищем действующего чемпиона в самом свежем предыдущем турнире
                        if not champion_found then
                            champion_code = get_champion(t_data)
                            champion_found = true
                        end
                    end
                end
            end
        end
    end

    if next(participants) == nil then
        return "В базе данных за " .. target_year .. " год турнир " .. target_tournament .. " не найден или не имеет участников."
    end

    -- === ПОДГОТОВКА ДАННЫХ ===
    local list = {}
    for code in pairs(participants) do
        local team_info = teams_module.getTeam(code)
        local short_name = team_info and team_info.short or code
        local full_name = team_info and team_info.full or code
        
        table.insert(list, {
            code = code,
            short = short_name,
            full = full_name,
            apps = appearances[code] or 1,
            is_champ = (code == champion_code)
        })
    end

    -- Сортировка: Чемпион идёт первым, остальные по алфавиту
    table.sort(list, function(a, b)
        if a.is_champ ~= b.is_champ then
            return a.is_champ 
        end
        return a.short < b.short
    end)

    -- === ОТРИСОВКА HTML ТАБЛИЦЫ ===
    local root = mw.html.create('table')
        :addClass('article-table')
        :attr('border', '1')
        :attr('cellspacing', '1')
        :attr('cellpadding', '1')
        :css('width', '500px')
    
    local num_teams = #list
    local rows_count = math.ceil(num_teams / 2)
    
    for r = 1, rows_count do
        local tr = root:tag('tr')
        
        for col = 1, 2 do
            local idx = (r - 1) * 2 + col
            local team = list[idx]
            
            if team then
                -- Ячейка с флагом
                tr:tag('td')
                    :attr('align', 'center')
                    :css('white-space', 'nowrap')
                    :wikitext(string.format('[[Файл:%s.jpg|50x100px]]', team.short))
                
                -- Ссылка на команду
                local link = (team.full == team.short) and string.format('[[%s]]', team.short) 
                             or string.format('[[%s]]', team.short)
                             
                tr:tag('td')
                    :attr('align', 'center')
                    :css('white-space', 'nowrap')
                    :wikitext(string.format("'''%s''' (%d)", link, team.apps))
            else
                -- Добиваем пустые ячейки, если количество команд нечётное
                tr:tag('td'):wikitext('')
                tr:tag('td'):wikitext('')
            end
        end
    end

    local header = "''(В скобках — общее количество участий в финальных турнирах)''"
    return header .. "\n" .. tostring(root)
end

return p