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

Материал из ЧТМ
Перейти к навигации Перейти к поиску
Нет описания правки
Версия 2.0
Строка 1: Строка 1:
-- ==========================================
-- ==========================================
-- Модуль:Статистика игроков по командам
-- Модуль:Статистика игроков по командам
-- Версия 2.0
-- Версия 2.0 (стабильная, теперь считаются все показатели,
-- можно постепенно допиливать мелкие недочёты)
-- ==========================================
-- ==========================================



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

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

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

Использование

Для голов (например, от 9):

{{#invoke:Статистика игроков по командам|build|award=goals|limit=9}}

Для ассистов (например, от 5):

{{#invoke:Статистика игроков по командам|build|award=assists|limit=5}}

Доступен также параметр worst, отображающий таблицы в перевёрнутом виде:

{{#invoke:Статистика игроков по командам|build|award=plus_minus|limit=-7|worst=yes}}

Поддерживающиеся параметры:

  • award=goals — Голы (с 2006).
  • award=assists — Голевые передачи (с 2026).
  • award=head_goals — Голы головой (с 2022).
  • award=heel_goals — Голы пяткой (с 2026).
  • award=free_kick_goals — Голы со штрафных (с 2026).
  • award=goalie_goals — Вратарские голы (забитые вратарем) (с 2022).
  • award=mega_tricks — Мега-трики (хет-трики, покеры и выше) (с 2006).
  • award=assist_mega_tricks — Ассистентские мега-трики (с 2026).
  • award=clean_sheets — «Сухие» матчи (с 2006).
  • award=pens_saved — Отраженные пенальти (с 2006).
  • award=clearances — Выносы из пустых ворот (с 2022).
  • award=mvp_goalie — Призы лучшему вратарю матча (с 2006).
  • award=yellow_cards — Жёлтые карточки (с 2038).
  • award=red_cards — Красные карточки (с 2038).
  • award=own_goals — Автоголы (с 2006).
  • award=caused_pens — «Привезенные» пенальти (фолы) (с 2026).
  • award=pens_missed — Незабитые пенальти (с 2006).
  • award=plus_minus — Плюс/Минус (с 2022).
  • award=mvp — Звания лучшего игрока матча (с 2006).
  • award=matches — Всего матчей за команду (с 2022).
  • award=field_matches — Матчи в качестве полевого игрока (с 2022).
  • award=avg_goals — Средняя результативность (голы за матч) (с 2022).
  • award=avg_assists — Среднее число передач за матч (с 2026).

-- ==========================================
-- Модуль:Статистика игроков по командам
-- Версия 2.0 (стабильная, теперь считаются все показатели, 
-- можно постепенно допиливать мелкие недочёты)
-- ==========================================

local M = {}

local Config = require('Module:Config')
local StatEngine = require('Module:StatEngine')
local Teams = require('Module:Data/Teams')

function M.build(frame)
    local award_type = frame.args.award or "goals"
    local worst_flag = (frame.args.worst == "yes" or frame.args.worst == "1")
    local m_conf = Config.metrics[award_type]
    
    if not m_conf then return "Ошибка: показатель '" .. tostring(award_type) .. "' не найден в Config.metrics" end

    local limit = tonumber(frame.args.limit) or 1
    local start_year = m_conf.start or 2006
    
    local is_goals = (award_type == "goals")
    local is_avg = m_conf.is_average
    local latest_year = Config.years[#Config.years]

    local valid_years = {}
    for _, y in ipairs(Config.years) do
        if y >= start_year then table.insert(valid_years, y) end
    end

    local combos = {}       
    local team_years = {}   
    local medals = {}       

    for _, year in ipairs(valid_years) do
        team_years[year] = {}
        medals[year] = {}
        
        local success, year_db = pcall(require, 'Module:Data/' .. year)
        if success and type(year_db) == "table" then
            
            for _, match in pairs(year_db) do
                if match.team1 then team_years[year][match.team1] = true end
                if match.team2 then team_years[year][match.team2] = true end
            end
            
            local year_awards
            if award_type == "goals" or award_type == "assists" then
                year_awards = StatEngine.getTournamentAwards(year, year_db, award_type)
            else
                year_awards = StatEngine.getGenericMetricByTeams(year, year_db, award_type, { worst = worst_flag })
            end
            
            for _, p in ipairs(year_awards) do
                local key = p.player .. "_" .. p.team_code
                
                if not combos[key] then
                    combos[key] = {
                        player = p.player,
                        team_code = p.team_code,
                        total_val = 0,
                        total_num = 0,
                        total_den = 0,
                        total_pens = 0,
                        years = {}
                    }
                end
                
                local c = combos[key]
                
                if is_avg then
                    c.total_num = c.total_num + (p.total.num or 0)
                    c.total_den = c.total_den + (p.total.den or 0)
                else
                    c.total_val = c.total_val + p.total
                end
                
                c.total_pens = c.total_pens + (p.pens or 0)
                c.years[year] = p.total
                
                local can_give_medals = true
                if year == latest_year and Config.is_latest_finished == false then
                    can_give_medals = false
                end
                
                if can_give_medals and p.color and p.color ~= "" then
                    medals[year][key] = p.color
                end
            end
        end
    end

    -- ==========================================
    -- УМНЫЙ ФИЛЬТР ЛИМИТОВ
    -- ==========================================
    local final_list = {}
    for _, c in pairs(combos) do
        local passes_limit = false
        
        if is_avg then
            passes_limit = (c.total_den >= limit and c.total_den > 0)
        else
            if worst_flag then
                -- Худшие (отсекаем всё, что больше -limit)
                passes_limit = (c.total_val <= -math.abs(limit))
            else
                -- Обычный лимит
                passes_limit = (c.total_val >= limit)
            end
        end
        
        if passes_limit then table.insert(final_list, c) end
    end

    -- ==========================================
    -- ГЛОБАЛЬНАЯ СОРТИРОВКА (С ИСКЛЮЧЕНИЕМ ДЛЯ ПЛЮС/МИНУС)
    -- ==========================================
    local is_asc = m_conf.sort_asc
    
    if award_type == "plus_minus" then
        if worst_flag then
            is_asc = true  -- Самые большие минусы идут наверх
        else
            is_asc = false -- Самые большие плюсы идут наверх
        end
    else
        if worst_flag then is_asc = not is_asc end
    end

    table.sort(final_list, function(a, b)
        local numA = is_avg and Config.utils.calc_avg(a.total_num, a.total_den) or a.total_val
        local numB = is_avg and Config.utils.calc_avg(b.total_num, b.total_den) or b.total_val

        if numA ~= numB then
            if is_asc then return numA < numB end
            return numA > numB
        end
        
        if is_goals and a.total_pens ~= b.total_pens then
            return a.total_pens < b.total_pens
        end
        
        local tb_a = { name = a.player .. a.team_code, total_val = numA, total_num = a.total_num, total_den = a.total_den, years = a.years }
        local tb_b = { name = b.player .. b.team_code, total_val = numB, total_num = b.total_num, total_den = b.total_den, years = b.years }
        
        return Config.tiebreaker(tb_a, tb_b, valid_years, is_avg, is_asc)
    end)

    -- ОТРИСОВКА
    local html = mw.html.create('table')
        :addClass(Config.styles.classes)
        :attr('border', Config.styles.border)
        :attr('cellspacing', Config.styles.cellspacing)
        :attr('cellpadding', Config.styles.cellpadding)

    local tr_head = html:tag('tr')
    tr_head:tag('th'):cssText(Config.styles.header):wikitext('Место')
    tr_head:tag('th'):cssText(Config.styles.header):wikitext('Игрок (Команда)')
    
    for _, year in ipairs(valid_years) do
        local short_year = string.sub(tostring(year), 3, 4)
        tr_head:tag('th'):cssText(Config.styles.header):wikitext("[[ЧТМ-" .. year .. "|'" .. short_year .. "]]")
    end
    
    if is_goals then
        tr_head:tag('th'):cssText(Config.styles.header):wikitext("ВСЕГО ''(с пен.)''")
    else
        tr_head:tag('th'):cssText(Config.styles.header):wikitext("ВСЕГО")
    end

    for i, c in ipairs(final_list) do
        local tr = html:tag('tr')
        
        tr:tag('td'):cssText(Config.styles.center_nowrap):wikitext(tostring(i))
        
        local team_name = Teams.getName(c.team_code, 'short')
        local p_t_text = "[[" .. c.player .. "]] ([[" .. team_name .. "]])"
        tr:tag('td'):cssText(Config.styles.center_nowrap):wikitext(p_t_text)
        
        for _, year in ipairs(valid_years) do
            local td = tr:tag('td')
            local style = Config.styles.center_nowrap .. ' '
            local key = c.player .. "_" .. c.team_code
            
            if medals[year] and medals[year][key] then
                style = style .. medals[year][key]
            end
            td:cssText(style)
            
            if not team_years[year] or (c.team_code ~= "Нейтрал" and not team_years[year][c.team_code]) then
                td:wikitext("") 
            else
                local val = c.years[year]
                if val == nil then
                    td:wikitext(is_avg and "0,00" or "0")
                else
                    local text_val = is_avg and Config.utils.format_avg(val.num, val.den) or Config.utils.format_val(award_type, val)
                    td:wikitext(text_val)
                end
            end
        end
        
        local total_num = is_avg and Config.utils.calc_avg(c.total_num, c.total_den) or c.total_val
        local total_text = "'''" .. (is_avg and Config.utils.format_avg(c.total_num, c.total_den) or Config.utils.format_val(award_type, total_num)) .. "'''"
        
        if is_goals and c.total_pens > 0 then
            total_text = total_text .. " (" .. c.total_pens .. ")"
        end
        
        tr:tag('td'):cssText(Config.styles.center_nowrap):wikitext(total_text)
    end

    return frame:preprocess(Config.styles.wiki_templates .. tostring(html))
end

return M