Модуль:Статистика игроков
Модуль предназначен для изменения статистики игроков по всей энциклопедии. Данные хранятся на подстранице Модуль:Статистика игроков/data.
Шаблоны для вызова данных
- {{СИ/Строка}} — основной шаблон строки на страницах статистики показателей
- {{Автоматическая статистика/Строка}} — основной шаблон строки в таблицах статистики игроков
- {{МСИ}} — простая цифра
- {{МСИ2}} — ссылка на игрока, тире и показатель
- {{МСИ/Сумма}} — сумма
- {{СИ}} — строка с 12 параметрами
- {{СИ/С2}} — строка с 2 параметрами
- {{СИ/С3}} — строка с 3 параметрами
Этот модуль входит в число избранных модулей ЧТМ Вики. |
local p = {}
local data = mw.loadData('Module:Статистика игроков/data')
-----------------------------------------------------------------------
-- КОНФИГУРАЦИЯ ЭПОХ (ГОДОВ) (для шаблона СИ/Строка)
-- Здесь мы прописываем, какие турниры учитываются для разных показателей.
-----------------------------------------------------------------------
local ALL_YEARS = {"2006", "2010", "2014", "2018", "2022", "2026", "2030", "2034", "2038", "2042", "2046"}
local METRIC_YEARS = {
-- Показатели с начала времён (11 турниров)
["Голы"] = ALL_YEARS,
["Игрок_матча"] = ALL_YEARS,
["Забитые_пенальти"] = ALL_YEARS,
["Незабитые_пенальти"] = ALL_YEARS,
["Отбитые_пенальти"] = ALL_YEARS,
["Матчи_на_ноль"] = ALL_YEARS,
["Автоголы"] = ALL_YEARS,
["Мега-трики"] = ALL_YEARS,
-- Показатели, которые начали считать позже (с 2022) - 7 турниров
["Матчи"] = {"2022", "2026", "2030", "2034", "2038", "2042", "2046"},
["Матчи_в_поле"] = {"2022", "2026", "2030", "2034", "2038", "2042", "2046"},
["Призы_игровых_дней"] = {"2022", "2026", "2030", "2034", "2038", "2042", "2046"},
["Призовые_места_игр_дней"] = {"2022", "2026", "2030", "2034", "2038", "2042", "2046"},
["Показатель_полезности"] = {"2022", "2026", "2030", "2034", "2038", "2042", "2046"},
["Выносы_из_пустых"] = {"2022", "2026", "2030", "2034", "2038", "2042", "2046"},
-- Показатели, которые начали считать с 2026 - 6 турниров
["Передачи"] = {"2026", "2030", "2034", "2038", "2042", "2046"},
["Голы_головой"] = {"2026", "2030", "2034", "2038", "2042", "2046"},
["Голы_пяточкой"] = {"2026", "2030", "2034", "2038", "2042", "2046"},
["Голы_со_штрафных"] = {"2026", "2030", "2034", "2038", "2042", "2046"},
["Мега-трики_голевых_передач"] = {"2026", "2030", "2034", "2038", "2042", "2046"},
["Привезённые_пенальти"] = {"2026", "2030", "2034", "2038", "2042", "2046"}
}
-- Старая функция (оставляем, чтобы ничего не сломать там, где она ещё используется)
function p.Statistics (frame)
return data[frame.args[1]]
end
-- НОВАЯ УНИВЕРСАЛЬНАЯ ФУНКЦИЯ
function p.UniversalRow(frame)
local place = frame.args[1] or ""
local player = frame.args[2] or ""
local stat_type = frame.args[3] or "Голы"
local pen_stat = frame.args[4] -- Опциональный показатель в скобках (например, Голы_с_пенальти)
-- 1. Определяем нужные годы
local years = METRIC_YEARS[stat_type] or ALL_YEARS
-- 2. МАГИЯ ШАБЛОНОВ: вычисляем нужный шаблон (С14, С9, С8 и т.д.)
-- Количество годов + 3 (Колонка места, Колонка Игрока, Колонка Суммы)
local tpl_name = "С" .. tostring(#years + 3)
-- 3. Формируем аргументы для шаблона С..
local player_link = "[[" .. string.gsub(player, "_", " ") .. "]]"
local c_args = { place, player_link }
local sum = 0
-- 4. Перебираем нужные годы, собираем статистику и суммируем
for _, year in ipairs(years) do
local key = player .. "/" .. stat_type .. "/" .. year
local val = data[key]
if val and val ~= "" then
table.insert(c_args, val)
-- Пытаемся превратить в число для суммы (работает и с отрицательными "-3")
local num = tonumber(val)
if num then sum = sum + num end
else
table.insert(c_args, "") -- Если в этот год не играл/не забивал
end
end
-- 5. Обработка суммы (возвращаем плюсы для "Показателя полезности", если сумма больше нуля)
local sum_str = tostring(sum)
if stat_type == "Показатель_полезности" and sum > 0 then
sum_str = "+" .. sum_str
end
table.insert(c_args, "'''" .. sum_str .. "'''")
-- 6. Запускаем нужный шаблон (например, С14 или С9)
local result = frame:expandTemplate{ title = tpl_name, args = c_args }
-- 7. Добавляем данные в скобках (если переданы)
if pen_stat and pen_stat ~= "" then
local pen_key = player .. "/" .. pen_stat
local pen_val = data[pen_key]
if pen_val and pen_val ~= "0" and pen_val ~= "" then
result = result .. " (" .. pen_val .. ")"
end
end
return result
end
-----------------------------------------------------------------------
-- КОНФИГУРАЦИЯ ДЛЯ ПРОФИЛЯ ИГРОКА (для шаблона Автоматическая статистика)
-----------------------------------------------------------------------
local ALL_YEARS = {"2006", "2010", "2014", "2018", "2022", "2026", "2030", "2034", "2038", "2042", "2046"}
local START_YEARS = {
["Матчи"] = "2022",
["Матчи_в_поле"] = "2022",
["Ср_результативность"] = "2022",
["Передачи"] = "2026",
["Ср_передачи"] = "2026",
["Мега-трики_голевых_передач"] = "2026",
["Голы_пяточкой"] = "2026",
["Голы_со_штрафных"] = "2026",
["Привезённые_пенальти"] = "2026",
["Призы_игровых_дней"] = "2022",
["Призовые_места_игр_дней"] = "2022",
["Показатель_полезности"] = "2022",
["Голы_головой"] = "2022",
["Выносы_из_пустых"] = "2022"
}
local NEGATIVE_STATS = {
["Незабитые_пенальти"] = true,
["Привезённые_пенальти"] = true,
["Автоголы"] = true
}
-----------------------------------------------------------------------
-- КАРТА ВСЕХ СТРОК ТАБЛИЦЫ ПРОФИЛЯ (Порядок, ID метрики, Заголовок)
-----------------------------------------------------------------------
local PROFILE_METRICS = {
{ id = "Матчи", title = "[[Матчи|<abbr title=\"Подсчитываются начиная с ЧТМ-2022\">Матчи</abbr>]]" },
{ id = "Матчи_в_поле", title = "{{Abbr|Матчи в поле|Подсчитываются начиная с ЧТМ-2022}}" },
{ id = "Голы", title = "[[Список всех авторов голов на ЧТМ|Голы]]" },
{ id = "Передачи", title = "[[Передачи|<abbr title=\"Подсчитываются начиная с ЧТМ-2026\">Передачи</abbr>]]" },
{ id = "Ср_результативность", title = "[[Средняя результативность|<abbr title=\"Подсчитывается начиная с ЧТМ-2022\">Ср. результативность</abbr>]]", avg_base = "Голы" },
{ id = "Ср_передачи", title = "{{Abbr|Передачи (ср. за матч)|Подсчитывается начиная с ЧТМ-2026}}", avg_base = "Передачи" },
{ id = "Игрок_матча", title = "[[Игрок матча]]" },
{ id = "Призы_игровых_дней", title = "[[Призы игровых дней|<abbr title=\"Подсчитываются начиная с ЧТМ-2022\">Призы игровых дней</abbr>]]" },
{ id = "Призовые_места_игр_дней", title = "[[Призы игровых дней#Призовые места игровых дней|<abbr title=\"Подсчитываются начиная с ЧТМ-2022\">Призовые места игр. дней</abbr>]]" },
{ id = "Показатель_полезности", title = "[[Показатель полезности|<abbr title=\"Подсчитывается начиная с ЧТМ-2022\">Показатель полезности</abbr>]]" },
{ id = "Мега-трики", title = "[[Мега-трики]]" },
{ id = "Мега-трики_голевых_передач", title = "[[Мега-трики голевых передач|<abbr title=\"Подсчитываются начиная с ЧТМ-2026\">Мега-трики голевых передач</abbr>]]" },
{ id = "Голы_головой", title = "[[Голы головой|<abbr title=\"Подсчитываются начиная с ЧТМ-2022\">Голы головой</abbr>]]" },
{ id = "Голы_пяточкой", title = "[[Голы пяточкой|<abbr title=\"Подсчитываются начиная с ЧТМ-2026\">Голы пяточкой</abbr>]]" },
{ id = "Голы_со_штрафных", title = "[[Голы со штрафных|<abbr title=\"Подсчитываются начиная с ЧТМ-2026\">Голы со штрафных</abbr>]]" },
{ id = "Выносы_из_пустых", title = "[[Выносы из пустых|<abbr title=\"Подсчитываются начиная с ЧТМ-2022\">Выносы из пустых</abbr>]]" },
{ id = "Забитые_пенальти", title = "[[Пенальти|Забитые пенальти]]" },
{ id = "Незабитые_пенальти", title = "Незабитые пенальти" },
{ id = "Отбитые_пенальти", title = "[[Список пенальти ЧТМ#Отбитые пенальти|Отбитые пенальти]]" },
{ id = "Привезённые_пенальти", title = "[[Привезённые пенальти|<abbr title=\"Подсчитываются начиная с ЧТМ-2026\">Привезённые пенальти</abbr>]]" },
{ id = "Игрок_матча_как_вратарь", title = "[[Игрок матча как вратарь]]" },
{ id = "Матчи_на_ноль", title = "[[Матчи на ноль]]" },
{ id = "Автоголы", title = "Автоголы" }
}
-- УМНАЯ ОЛИМПИЙСКАЯ ФУНКЦИЯ ВЫДАЧИ МЕДАЛЕЙ (Оставляем как было)
local function evaluateRank(current_val, all_scores, metric)
if not current_val or current_val == 0 then return nil end
if #all_scores == 0 then return nil end
if metric == "Показатель_полезности" then
if current_val > 0 then
table.sort(all_scores, function(a, b) return a > b end)
local rank = 1
for i, v in ipairs(all_scores) do
if v == current_val then rank = i break end
end
if rank == 1 then return "GO" end
if rank == 2 then return "SI" end
if rank == 3 then return "BR" end
if rank == 4 then return "WO" end
elseif current_val < 0 then
table.sort(all_scores, function(a, b) return a < b end)
if current_val == all_scores[1] then return "lightsalmon" end
end
return nil
end
if NEGATIVE_STATS[metric] then
table.sort(all_scores, function(a, b) return a > b end)
if current_val == all_scores[1] then return "lightsalmon" end
return nil
end
table.sort(all_scores, function(a, b) return a > b end)
local rank = 1
for i, v in ipairs(all_scores) do
if v == current_val then rank = i break end
end
if rank == 1 then return "GO" end
if rank == 2 then return "SI" end
if rank == 3 then return "BR" end
if rank == 4 then return "WO" end
return nil
end
-- Ранжирование внутри одного года
local function getRankColor(metric, year, current_val, avg_base, current_player_matches)
local scores = {}
if avg_base and avg_base ~= "" then
if current_player_matches < 20 then return nil end
local players = {}
for key, _ in pairs(data) do
local p = string.match(key, "^(.-)/")
if p then players[p] = true end
end
for p, _ in pairs(players) do
local act = tonumber(data[p .. "/" .. avg_base .. "/" .. year]) or 0
local mat = tonumber(data[p .. "/Матчи_в_поле/" .. year]) or 0
if mat >= 20 then
local p_val = tonumber(string.format("%.2f", act / mat))
if p_val and p_val ~= 0 then table.insert(scores, p_val) end
end
end
else
for key, v in pairs(data) do
local p, m, y = string.match(key, "^(.-)/([^/]+)/([^/]+)$")
if m == metric and y == year then
local num = tonumber(v)
if num and num ~= 0 then table.insert(scores, num) end
end
end
end
return evaluateRank(current_val, scores, metric)
end
-- Подсчет суммы одного игрока
local function calculatePlayerTotal(player, metric, avg_base, start_year)
local is_active = false
local t_acts = 0
local t_mats = 0
local p_val = 0
for _, y in ipairs(ALL_YEARS) do
if y == start_year then is_active = true end
if is_active then
if avg_base and avg_base ~= "" then
local act = tonumber(data[player .. "/" .. avg_base .. "/" .. y]) or 0
local mat = tonumber(data[player .. "/Матчи_в_поле/" .. y]) or 0
if mat > 0 then
t_acts = t_acts + act
t_mats = t_mats + mat
end
else
p_val = p_val + (tonumber(data[player .. "/" .. metric .. "/" .. y]) or 0)
end
end
end
if avg_base and avg_base ~= "" then
if t_mats > 0 then return tonumber(string.format("%.2f", t_acts / t_mats)), t_mats end
return 0, 0
else
return p_val, 0
end
end
-- Ранжирование ОБЩЕЙ СУММЫ
local function getSumRankColor(metric, avg_base, current_val, start_year, total_matches)
if avg_base and avg_base ~= "" then
if total_matches < 20 then return nil end
end
local players = {}
for key, _ in pairs(data) do
local p = string.match(key, "^(.-)/")
if p then players[p] = true end
end
local scores = {}
for p, _ in pairs(players) do
local p_val, p_mats = calculatePlayerTotal(p, metric, avg_base, start_year)
if avg_base and avg_base ~= "" then
if p_val and p_val ~= 0 and p_mats >= 20 then table.insert(scores, p_val) end
else
if p_val and p_val ~= 0 then table.insert(scores, p_val) end
end
end
return evaluateRank(current_val, scores, metric)
end
-----------------------------------------------------------------------
-- ВНУТРЕННЯЯ ФУНКЦИЯ: Генерирует одну строку (бывшая ProfileRow)
-----------------------------------------------------------------------
local function generateRow(frame, player, metric, title, avg_base)
local tpl_name = "С" .. tostring(#ALL_YEARS + 2)
local c_args = { frame:preprocess(title) }
local start_year = START_YEARS[metric] or "2006"
local is_active = false
local total_val = 0
local total_matches = 0
for i, year in ipairs(ALL_YEARS) do
if year == start_year then is_active = true end
local col_index = i + 1
if not is_active then
table.insert(c_args, "")
c_args["ц" .. col_index] = "rgb(235,243,254)"
else
local val = ""
local raw_val = 0
if avg_base and avg_base ~= "" then
local acts = tonumber(data[player .. "/" .. avg_base .. "/" .. year]) or 0
local matches_field = tonumber(data[player .. "/Матчи_в_поле/" .. year]) or 0
if matches_field > 0 then
raw_val = tonumber(string.format("%.2f", acts / matches_field))
val = string.format("%.2f", raw_val)
local color = getRankColor(metric, year, raw_val, avg_base, matches_field)
if color then c_args["ц" .. col_index] = color end
total_val = total_val + acts
total_matches = total_matches + matches_field
end
else
local raw_str = data[player .. "/" .. metric .. "/" .. year]
if raw_str and raw_str ~= "" then
raw_val = tonumber(raw_str) or 0
if metric == "Показатель_полезности" and raw_val > 0 then
val = "+" .. tostring(raw_val)
else
val = tostring(raw_val)
end
total_val = total_val + raw_val
local color = getRankColor(metric, year, raw_val, nil, 0)
if color then c_args["ц" .. col_index] = color end
end
end
table.insert(c_args, val)
end
end
local final_sum_val = 0
local final_sum_str = ""
if avg_base and avg_base ~= "" then
if total_matches > 0 then
final_sum_val = tonumber(string.format("%.2f", total_val / total_matches))
final_sum_str = string.format("%.2f", final_sum_val)
else
final_sum_str = "0.00"
end
else
final_sum_val = total_val
final_sum_str = tostring(total_val)
if metric == "Показатель_полезности" and total_val > 0 then
final_sum_str = "+" .. final_sum_str
end
end
table.insert(c_args, "'''" .. final_sum_str .. "'''")
if final_sum_val ~= 0 then
local sum_color = getSumRankColor(metric, avg_base, final_sum_val, start_year, total_matches)
if sum_color then c_args["ц" .. (#ALL_YEARS + 2)] = sum_color end
end
return frame:expandTemplate{ title = tpl_name, args = c_args }
end
-----------------------------------------------------------------------
-- НОВАЯ СУПЕР-ФУНКЦИЯ: Отрисовывает таблицу профиля ЦЕЛИКОМ!
-----------------------------------------------------------------------
function p.RenderFullProfile(frame)
local player = frame.args[1] or frame:getParent().args[1]
if not player or player == "" then return "" end
local lines = {}
-- 1. Шапка таблицы (открываем таблицу и задаем заголовок)
table.insert(lines, frame:expandTemplate{ title = 'Статистика/Заголовок', args = { player } })
-- 2. В цикле генерируем абсолютно все строки из нашего массива PROFILE_METRICS
for _, m in ipairs(PROFILE_METRICS) do
-- Вызываем внутреннюю генерацию строки (аналог бывшего ProfileRow)
local row = generateRow(frame, player, m.id, m.title, m.avg_base)
table.insert(lines, row)
end
-- 3. Закрываем таблицу
table.insert(lines, "|}")
-- Соединяем всё с переносами каретки
return table.concat(lines, "\n")
end
-- Старая функция оставлена на всякий случай (мало ли где-то ещё осталась)
function p.ProfileRow(frame)
return generateRow(frame, frame.args[1], frame.args[2], frame.args[3], frame.args[4])
end
-----------------------------------------------------------------------
-- АБСОЛЮТНО НАГЛАЯ ФУНКЦИЯ: Автоматическая полная таблица по показателю
-----------------------------------------------------------------------
function p.RenderStatTable(frame)
local main_metric = frame.args[1] or "Голы"
local pen_stat = frame.args[2]
local current_tournament_matches = tonumber(frame.args[3]) or 64 -- Третий параметр для текущего ЧТМ
-- Определяем годы. Для "Матчей в воротах" берём годы от обычных "Матчей"
local years_lookup = main_metric
if main_metric == "Матчи_в_воротах" then years_lookup = "Матчи" end
local years = METRIC_YEARS[years_lookup] or ALL_YEARS
-- Переменные для финальной строки "ВСЕГО"
local col_totals = {}
for i = 1, #years do col_totals[i] = 0 end
local grand_total = 0
local total_pens = 0
-- ВНУТРЕННЯЯ ПОДФУНКЦИЯ: собирает, сортирует и генерирует строки
local function generate_rows(metric_name, p_stat, hide_rank)
local players_set = {}
for key, _ in pairs(data) do
local p_match = string.match(key, "^(.+)/[^/]+/%d%d%d%d$")
if p_match then
players_set[p_match] = true
else
p_match = string.match(key, "^(.+)/[^/]+$")
if p_match then players_set[p_match] = true end
end
end
local list = {}
for player, _ in pairs(players_set) do
local pdata = { name = player, total = 0, years = {}, has_data = false, pen_total = 0 }
for i, year in ipairs(years) do
local val_str = ""
local num = 0
-- ИСКЛЮЧЕНИЕ: Считаем матчи в воротах (Матчи минус Матчи в поле)
if metric_name == "Матчи_в_воротах" then
local val_all = data[player .. "/Матчи/" .. year]
if val_all and val_all ~= "" then
local m_all = tonumber(val_all) or 0
local m_field = tonumber(data[player .. "/Матчи_в_поле/" .. year]) or 0
num = m_all - m_field
val_str = tostring(num)
end
else
val_str = data[player .. "/" .. metric_name .. "/" .. year]
num = tonumber(val_str) or 0
end
pdata.years[i] = { raw = val_str, num = num }
pdata.total = pdata.total + num
if val_str and val_str ~= "" then
pdata.has_data = true
end
end
if p_stat and p_stat ~= "" then
local p_val = tonumber(data[player .. "/" .. p_stat]) or 0
if p_val ~= 0 then pdata.pen_total = p_val end
end
if pdata.has_data then
if pdata.total ~= 0 or metric_name == "Показатель_полезности" then
table.insert(list, pdata)
end
end
end
table.sort(list, function(a, b)
if a.total ~= b.total then return a.total > b.total end
if metric_name == "Голы" and p_stat and p_stat ~= "" then
if a.pen_total ~= b.pen_total then return a.pen_total < b.pen_total end
end
local sumA, sumB = a.total, b.total
for i = #years, 1, -1 do
sumA = sumA - a.years[i].num
sumB = sumB - b.years[i].num
if sumA ~= sumB then return sumA > sumB end
end
return a.name < b.name
end)
local html_rows = {}
for rank, p in ipairs(list) do
local row = {'|-'}
if hide_rank then
table.insert(row, '| style="text-align:center;" | ')
else
table.insert(row, '| style="text-align:center;" | ' .. rank)
end
local p_link = "[[" .. string.gsub(p.name, "_", " ") .. "]]"
table.insert(row, '| style="text-align:center; white-space:nowrap;" | ' .. p_link)
for i, year in ipairs(years) do
local v_str = ""
if p.years[i].raw and p.years[i].raw ~= "" then
v_str = p.years[i].raw
-- ИСПРАВЛЕНИЕ: Добавляем плюс, только если его нет в оригинальной строке
if metric_name == "Показатель_полезности" and p.years[i].num > 0 and not string.match(v_str, "^%+") then
v_str = "+" .. v_str
end
end
table.insert(row, '| style="text-align:center;" | ' .. v_str)
-- Копим общую сумму колонки
col_totals[i] = col_totals[i] + p.years[i].num
end
local tot_str = tostring(p.total)
if metric_name == "Показатель_полезности" and p.total > 0 then
tot_str = "+" .. tot_str
end
if p.pen_total > 0 then
tot_str = "'''" .. tot_str .. "''' (" .. p.pen_total .. ")"
else
tot_str = "'''" .. tot_str .. "'''"
end
table.insert(row, '| style="text-align:center;" | ' .. tot_str)
-- Копим общие итоги
grand_total = grand_total + p.total
total_pens = total_pens + p.pen_total
table.insert(html_rows, table.concat(row, "\n"))
end
return table.concat(html_rows, "\n")
end
-- НАЧАЛО ОТРИСОВКИ ТАБЛИЦЫ
local html = {}
table.insert(html, '{{ПШТ}}{{стиль столбцов}}')
table.insert(html, '{| border="1" cellspacing="1" cellpadding="1" class="article-table sortable ts-stickytableheader"')
-- Шапка
local header_row = {'|-', '! style="background-color:#e0f0ff;" | Место !! style="background-color:#e0f0ff;" | Игрок'}
for _, year in ipairs(years) do
local short_year = "'" .. string.sub(year, 3, 4)
table.insert(header_row, '! style="background-color:#e0f0ff;" | [[' .. year .. '|' .. short_year .. ']]')
end
local total_text = '! style="background-color:#e0f0ff;" | ВСЕГО'
if pen_stat and pen_stat ~= "" then
total_text = '! style="background-color:#e0f0ff;" | ВСЕГО<br>\'\'(в скобках —<br>с<br>пенальти)\'\''
end
table.insert(header_row, total_text)
table.insert(html, table.concat(header_row, "\n"))
-- Запускаем генерацию для основного показателя
table.insert(html, generate_rows(main_metric, pen_stat, false))
-- ИСКЛЮЧЕНИЕ: Если это Голы, прикрепляем Автоголы
if main_metric == "Голы" then
local ag_header = {'|-'}
table.insert(ag_header, '| style="background-color:silver;" | ')
table.insert(ag_header, '| style="background-color:silver; text-align:center;" | \'\'\'Автоголы\'\'\'')
for i = 1, #years do
table.insert(ag_header, '| style="background-color:silver;" | ')
end
table.insert(ag_header, '| style="background-color:silver;" | ')
table.insert(html, table.concat(ag_header, "\n"))
table.insert(html, generate_rows("Автоголы", nil, true))
end
-- ИСКЛЮЧЕНИЕ: Для Голов добавляем 45 к 2006 году
if main_metric == "Голы" then
for i, year in ipairs(years) do
if year == "2006" then
col_totals[i] = col_totals[i] + 45
grand_total = grand_total + 45
end
end
end
-- ИСКЛЮЧЕНИЕ: Хардкодим количество реальных матчей на турнирах с 2022 года
if main_metric == "Матчи" then
grand_total = 229 -- Добавляем матчи первых четырех турниров (47+54+64+64)
for i, year in ipairs(years) do
if i == #years then
-- Для последнего турнира берем цифру из 3-го параметра шаблона
col_totals[i] = current_tournament_matches
else
-- Все завершенные с 2022 года турниры имели по 64 матча
col_totals[i] = 64
end
grand_total = grand_total + col_totals[i]
end
end
-- ИСКЛЮЧЕНИЕ: Убираем строку ВСЕГО для некоторых показателей
if main_metric ~= "Матчи_в_поле" and main_metric ~= "Матчи_в_воротах" and main_metric ~= "Показатель_полезности" then
local t_row = {'|-'}
table.insert(t_row, '|') -- пустая ячейка под местом
table.insert(t_row, '| style="text-align:center;" | \'\'\'ВСЕГО\'\'\'')
for i, _ in ipairs(years) do
local s_str = tostring(col_totals[i])
table.insert(t_row, '| style="text-align:center;" | \'\'\'' .. s_str .. '\'\'\'')
end
local g_str = tostring(grand_total)
if total_pens > 0 then
g_str = "\'\'\'" .. g_str .. "\'\'\' (" .. total_pens .. ")"
else
g_str = "\'\'\'" .. g_str .. "\'\'\'"
end
-- ИСКЛЮЧЕНИЕ: Добавляем сноску к общей сумме матчей
if main_metric == "Матчи" then
g_str = g_str .. " <ref>С учётом всех матчей до ЧТМ-2022.</ref>"
end
table.insert(t_row, '| style="text-align:center;" | ' .. g_str)
table.insert(html, table.concat(t_row, "\n"))
end
table.insert(html, '|}')
return frame:preprocess(table.concat(html, "\n"))
end
-----------------------------------------------------------------------
-- СПЕЦИАЛЬНАЯ ФУНКЦИЯ: Средняя результативность / Средние передачи
-----------------------------------------------------------------------
function p.RenderAvgTable(frame)
local metric = frame.args[1] or "Голы"
local years, col_name, avg_col_name, group_titles
-- Настраиваем переменные в зависимости от того, что считаем
if metric == "Передачи" then
years = {"2026", "2030", "2034", "2038", "2042", "2046"}
col_name = "Передачи"
avg_col_name = "Ср. пер."
group_titles = {
[1] = "Не менее 20 матчей в поле",
[2] = "От 5 до 19 матчей в поле",
[3] = "Менее 5 матчей в поле",
[4] = "Вообще не отдавали"
}
else
metric = "Голы"
years = {"2022", "2026", "2030", "2034", "2038", "2042", "2046"}
col_name = "Голы"
avg_col_name = "Ср. рез."
group_titles = {
[1] = "Не менее 20 матчей в поле",
[2] = "От 5 до 19 матчей в поле",
[3] = "Менее 5 матчей в поле",
[4] = "Вообще не забивали"
}
end
-- Вспомогательная функция для подсчета среднего
local function calc_avg(v, m)
if m == 0 then return 0 end
return v / m
end
-- 1. Собираем имена всех игроков
local player_names = {}
for key, _ in pairs(data) do
local p_match = string.match(key, "^(.+)/[^/]+/%d%d%d%d$") or string.match(key, "^(.+)/[^/]+$")
if p_match then player_names[p_match] = true end
end
-- 2. Вытаскиваем стату и считаем показатели
local list = {}
for player, _ in pairs(player_names) do
local pdata = {
name = player,
total_m = 0,
total_val = 0,
years = {}
}
local has_data = false
for i, y in ipairs(years) do
-- Обязательно берем матчи в поле за ТОТ ЖЕ год
local m = tonumber(data[player .. "/Матчи_в_поле/" .. y]) or 0
local v = tonumber(data[player .. "/" .. metric .. "/" .. y]) or 0
pdata.years[i] = { m = m, v = v }
pdata.total_m = pdata.total_m + m
pdata.total_val = pdata.total_val + v
if m > 0 then has_data = true end
end
-- Если игрок выходил в поле хотя бы раз в рамках заданных годов
if has_data then
pdata.avg = calc_avg(pdata.total_val, pdata.total_m)
-- Определяем группу (касту)
if pdata.total_val == 0 then
pdata.group = 4 -- Вообще не забивали / не отдавали
elseif pdata.total_m >= 20 then
pdata.group = 1 -- Элита (>= 20)
elseif pdata.total_m >= 5 then
pdata.group = 2 -- Средняки (5 - 19)
else
pdata.group = 3 -- Мало играли (< 5)
end
table.insert(list, pdata)
end
end
-- 3. СЛОЖНАЯ СОРТИРОВКА
table.sort(list, function(a, b)
-- Сначала сортируем по группам (1, 2, 3, 4)
if a.group ~= b.group then
return a.group < b.group
end
-- Внутри группы "Вообще не забивали / не отдавали"
if a.group == 4 then
-- Меньше матчей -> выше место
if a.total_m ~= b.total_m then return a.total_m < b.total_m end
return a.name < b.name
end
-- Внутри групп с успешными действиями (1, 2, 3)
local strA = string.format("%.2f", a.avg)
local strB = string.format("%.2f", b.avg)
if strA ~= strB then
return tonumber(strA) > tonumber(strB)
end
-- Если средняя в точности равна, отсекаем турниры с конца
local sumA_v, sumA_m = a.total_val, a.total_m
local sumB_v, sumB_m = b.total_val, b.total_m
for i = #years, 1, -1 do
sumA_v = sumA_v - a.years[i].v
sumA_m = sumA_m - a.years[i].m
sumB_v = sumB_v - b.years[i].v
sumB_m = sumB_m - b.years[i].m
local tA = string.format("%.2f", calc_avg(sumA_v, sumA_m))
local tB = string.format("%.2f", calc_avg(sumB_v, sumB_m))
if tA ~= tB then
return tonumber(tA) > tonumber(tB)
end
end
return a.name < b.name
end)
-- 4. ГЕНЕРАЦИЯ ТАБЛИЦЫ
local html = {}
table.insert(html, '{{ПШТ}}{{стиль столбцов}}')
table.insert(html, '{| border="1" cellspacing="1" cellpadding="1" class="article-table sortable ts-stickytableheader"')
-- Шапка
local h = {'|-', '! style="background-color:#e0f0ff;" | Место !! style="background-color:#e0f0ff;" | Игрок !! style="background-color:#e0f0ff;" | Матчи<br>в поле !! style="background-color:#e0f0ff;" | ' .. col_name .. ' !! style="background-color:#e0f0ff;" | ' .. avg_col_name}
for _, y in ipairs(years) do
local short_year = "'" .. string.sub(y, 3, 4)
table.insert(h, '! style="background-color:#e0f0ff;" | [[' .. y .. '|' .. short_year .. ']]')
end
table.insert(html, table.concat(h, "\n"))
local current_group = 0
local rank = 1
for _, p in ipairs(list) do
if p.group ~= current_group then
current_group = p.group
local colspan = 5 + #years
table.insert(html, '|-')
table.insert(html, '| colspan="' .. colspan .. '" style="background-color:silver; text-align:center;" | \'\'\'' .. group_titles[current_group] .. '\'\'\'')
end
local row = {'|-'}
-- Место
table.insert(row, '| style="text-align:center;" | ' .. rank)
-- Имя
local p_link = "[[" .. string.gsub(p.name, "_", " ") .. "]]"
table.insert(row, '| style="text-align:center; white-space:nowrap;" | ' .. p_link)
-- Матчи в поле и Голы/Передачи
table.insert(row, '| style="text-align:center;" | ' .. p.total_m)
table.insert(row, '| style="text-align:center;" | ' .. p.total_val)
-- Итоговая средняя
local avg_style = 'style="text-align:center; font-weight:bold;'
if p.total_m < 20 then
avg_style = avg_style .. ' background-color:lightsalmon;'
end
avg_style = avg_style .. '"'
table.insert(row, '| ' .. avg_style .. ' | ' .. string.format("%.2f", p.avg))
-- Года
for i, _ in ipairs(years) do
local m = p.years[i].m
local v = p.years[i].v
if m == 0 then
table.insert(row, '| style="text-align:center;" | ')
else
local y_avg = string.format("%.2f", v / m)
local cell_style = 'style="text-align:center;'
if m < 20 then
cell_style = cell_style .. ' background-color:lightsalmon;'
end
cell_style = cell_style .. '"'
table.insert(row, '| ' .. cell_style .. ' | ' .. y_avg)
end
end
table.insert(html, table.concat(row, "\n"))
rank = rank + 1
end
table.insert(html, '|}')
return frame:preprocess(table.concat(html, "\n"))
end
-----------------------------------------------------------------------
-- УЛЬТРА-ФУНКЦИЯ: Автоматические таблицы пенальти (Хронология, Результаты, Турниры)
-----------------------------------------------------------------------
function p.RenderPenalties(frame)
local mode = frame.args[1] or "Хронология" -- Хронология / Результаты / ПоТурнирам
local time_type = frame.args[2] or "Все" -- Все / Игровое
local spec_year = frame.args[3] -- Год (только для режима "Результаты")
local ALL_YEARS = {"2006", "2010", "2014", "2018", "2022", "2026", "2030", "2034", "2038", "2042", "2046"}
-- Вспомогательная функция: парсинг строки "г/вр/в/м/шт/п"
local function parse_pen_str(str)
if not str or str == "" then return 0, 0, 0, 0, 0, 0 end
local g, k, o, w, p_post, c = string.match(str, "(%d+)/(%d+)/(%d+)/(%d+)/(%d+)/(%d+)")
return tonumber(g) or 0, tonumber(k) or 0, tonumber(o) or 0, tonumber(w) or 0, tonumber(p_post) or 0, tonumber(c) or 0
end
-- Вспомогательная функция: сбор статы игрока за конкретный год
local function get_player_year_stats(player, year, t_type)
local g, k, o, w, p_post, c = 0, 0, 0, 0, 0, 0
-- Игровое время
local s1 = data[player .. "/Пенальти_Игровое/" .. year]
local g1, k1, o1, w1, p1, c1 = parse_pen_str(s1)
g = g + g1; k = k + k1; o = o + o1; w = w + w1; p_post = p_post + p1; c = c + c1
-- Серии (только если тип "Все")
if t_type == "Все" then
local s2 = data[player .. "/Пенальти_Серии/" .. year]
local g2, k2, o2, w2, p2, c2 = parse_pen_str(s2)
g = g + g2; k = k + k2; o = o + o2; w = w + w2; p_post = p_post + p2; c = c + c2
end
local u = g + k + o + w + p_post + c
return u, g, k, o, w, p_post, c
end
-- Математика: Показатель и Процент
local function calc_pok(g, u) return g - (u - g) * 2 end
local function format_pok(pok) return pok > 0 and "+" .. pok or tostring(pok) end
local function format_pct(g, u)
if u == 0 then return "0" end
local val = math.floor((g / u * 100) * 100 + 0.5) / 100
local str = string.format("%.2f", val)
str = string.gsub(str, "%.00$", "")
str = string.gsub(str, "(%..-)0+$", "%1")
return str
end
-- РЕЖИМ 3: ПО ТУРНИРАМ (Вообще без игроков)
if mode == "ПоТурнирам" then
local players_set = {}
for key, _ in pairs(data) do
local p_match = string.match(key, "^(.+)/Пенальти_")
if p_match then players_set[p_match] = true end
end
local html = {}
table.insert(html, '{{ПШТ}}{{стиль столбцов}}')
table.insert(html, '{| border="1" cellspacing="1" cellpadding="1" class="article-table sortable ts-stickytableheader"')
table.insert(html, '|- \n! style="background-color:#e0f0ff;" | № \n! style="background-color:#e0f0ff;" | ЧТМ \n! style="background-color:#e0f0ff;" | % \n! style="background-color:#e0f0ff;" | [[Лучший пенальтист#Система определения победителя|Показатель]] \n! style="background-color:#e0f0ff;" | Удары \n! style="background-color:#e0f0ff;" | Голы \n! style="background-color:#e0f0ff;" | вр. \n! style="background-color:#e0f0ff;" | в. \n! style="background-color:#e0f0ff;" | м. \n! style="background-color:#e0f0ff;" | шт. \n! style="background-color:#e0f0ff;" | п.')
local tot_u, tot_g, tot_k, tot_o, tot_w, tot_p, tot_c = 0,0,0,0,0,0,0
local rank = 1
for _, year in ipairs(ALL_YEARS) do
local y_u, y_g, y_k, y_o, y_w, y_p, y_c = 0,0,0,0,0,0,0
for player, _ in pairs(players_set) do
local u, g, k, o, w, p_post, c = get_player_year_stats(player, year, time_type)
y_u = y_u + u; y_g = y_g + g; y_k = y_k + k; y_o = y_o + o; y_w = y_w + w; y_p = y_p + p_post; y_c = y_c + c
end
if y_u > 0 then
table.insert(html, '|- \n| style="text-align:center;" | ' .. rank .. ' \n| style="text-align:center;" | [[' .. year .. ']] \n| style="text-align:center;" | ' .. format_pct(y_g, y_u) .. ' \n| style="text-align:center; font-weight:bold;" | ' .. format_pok(calc_pok(y_g, y_u)) .. ' \n| style="text-align:center; font-weight:bold;" | ' .. y_u .. ' \n| style="text-align:center; font-weight:bold;" | ' .. y_g .. ' \n| style="text-align:center;" | ' .. y_k .. ' \n| style="text-align:center;" | ' .. y_o .. ' \n| style="text-align:center;" | ' .. y_w .. ' \n| style="text-align:center;" | ' .. y_p .. ' \n| style="text-align:center;" | ' .. y_c)
rank = rank + 1
tot_u = tot_u + y_u; tot_g = tot_g + y_g; tot_k = tot_k + y_k; tot_o = tot_o + y_o; tot_w = tot_w + y_w; tot_p = tot_p + y_p; tot_c = tot_c + y_c
end
end
table.insert(html, '|- \n| colspan="2" style="text-align:center;" | \'\'\'ВСЕГО\'\'\' \n| style="text-align:center; font-weight:bold;" | ' .. format_pct(tot_g, tot_u) .. ' \n| style="text-align:center; font-weight:bold;" | ' .. format_pok(calc_pok(tot_g, tot_u)) .. ' \n| style="text-align:center; font-weight:bold;" | ' .. tot_u .. ' \n| style="text-align:center; font-weight:bold;" | ' .. tot_g .. ' \n| style="text-align:center; font-weight:bold;" | ' .. tot_k .. ' \n| style="text-align:center; font-weight:bold;" | ' .. tot_o .. ' \n| style="text-align:center; font-weight:bold;" | ' .. tot_w .. ' \n| style="text-align:center; font-weight:bold;" | ' .. tot_p .. ' \n| style="text-align:center; font-weight:bold;" | ' .. tot_c)
table.insert(html, '|}')
return frame:preprocess(table.concat(html, "\n"))
end
-- СБОР ИГРОКОВ (Для Хронологии и Результатов)
local players_set = {}
for key, _ in pairs(data) do
local p_match = string.match(key, "^(.+)/Пенальти_")
if p_match then players_set[p_match] = true end
end
local list = {}
for player, _ in pairs(players_set) do
local pdata = {name = player, u=0, g=0, k=0, o=0, w=0, p=0, c=0, years = {}}
for i, year in ipairs(ALL_YEARS) do
local y_u, y_g, y_k, y_o, y_w, y_p, y_c = get_player_year_stats(player, year, time_type)
pdata.years[i] = {u = y_u, g = y_g}
-- Если не выбран конкретный год ИЛИ год совпадает с выбранным
if not spec_year or spec_year == "" or spec_year == year then
pdata.u = pdata.u + y_u; pdata.g = pdata.g + y_g; pdata.k = pdata.k + y_k
pdata.o = pdata.o + y_o; pdata.w = pdata.w + y_w; pdata.p = pdata.p + y_p; pdata.c = pdata.c + y_c
end
end
if pdata.u > 0 then
pdata.pok = calc_pok(pdata.g, pdata.u)
pdata.stvor = pdata.g + pdata.k
pdata.frame = pdata.stvor + pdata.p + pdata.c
table.insert(list, pdata)
end
end
-- УМНАЯ СОРТИРОВКА (С учетом всех твоих условий)
table.sort(list, function(a, b)
if a.pok ~= b.pok then return a.pok > b.pok end
if a.g ~= b.g then return a.g > b.g end
-- Отсечение последних турниров (только если мы смотрим общую таблицу, а не один год)
if not spec_year or spec_year == "" then
local sumA, sumB = a.g, b.g
for i = #ALL_YEARS, 1, -1 do
sumA = sumA - a.years[i].g
sumB = sumB - b.years[i].g
if sumA ~= sumB then return sumA > sumB end
end
end
-- Доп. параметры только для режима Результатов
if mode == "Результаты" then
if a.stvor ~= b.stvor then return a.stvor > b.stvor end
if a.frame ~= b.frame then return a.frame > b.frame end
end
return a.name < b.name
end)
-- ГЕНЕРАЦИЯ HTML
local html = {}
table.insert(html, '{{ПШТ}}{{стиль столбцов}}')
table.insert(html, '{| border="1" cellspacing="1" cellpadding="1" class="article-table sortable ts-stickytableheader"')
-- РЕЖИМ 1: ХРОНОЛОГИЯ
if mode == "Хронология" then
local h = {'|- \n! style="background-color:#e0f0ff;" | Место \n! style="background-color:#e0f0ff;" | Игрок'}
for _, y in ipairs(ALL_YEARS) do
table.insert(h, '! style="background-color:#e0f0ff;" | [[' .. y .. '|\'' .. string.sub(y, 3, 4) .. ']]')
end
table.insert(h, '! style="background-color:#e0f0ff;" | ВСЕГО \n! style="background-color:#e0f0ff;" | % \n! style="background-color:#e0f0ff;" | [[Лучший пенальтист#Система определения победителя|Показатель]]')
table.insert(html, table.concat(h, "\n"))
local col_u, col_g = {}, {}
for i = 1, #ALL_YEARS do col_u[i]=0; col_g[i]=0 end
local tot_u, tot_g = 0, 0
for rank, p in ipairs(list) do
local row = {'|- \n| style="text-align:center;" | ' .. rank .. ' \n| style="text-align:center; white-space:nowrap;" | [[' .. string.gsub(p.name, "_", " ") .. ']]'}
for i, year in ipairs(ALL_YEARS) do
local u, g = p.years[i].u, p.years[i].g
col_u[i] = col_u[i] + u; col_g[i] = col_g[i] + g
if u > 0 then
table.insert(row, '| style="text-align:center;" | ' .. u .. '/' .. g)
else
table.insert(row, '| style="text-align:center;" | 0')
end
end
tot_u = tot_u + p.u; tot_g = tot_g + p.g
table.insert(row, '| style="text-align:center;" | \'\'\'' .. p.u .. '/' .. p.g .. '\'\'\' \n| style="text-align:center;" | ' .. format_pct(p.g, p.u) .. '% \n| style="text-align:center; font-weight:bold;" | ' .. format_pok(p.pok))
table.insert(html, table.concat(row, "\n"))
end
local t_row = {'|- \n| \n| style="text-align:center;" | \'\'\'ВСЕГО\'\'\''}
for i = 1, #ALL_YEARS do
if col_u[i] > 0 then
table.insert(t_row, '| style="text-align:center; font-weight:bold;" | ' .. col_u[i] .. '/' .. col_g[i])
else
table.insert(t_row, '| style="text-align:center; font-weight:bold;" | 0')
end
end
table.insert(t_row, '| style="text-align:center; font-weight:bold;" | ' .. tot_u .. '/' .. tot_g .. ' \n| style="text-align:center; font-weight:bold;" | ' .. format_pct(tot_g, tot_u) .. '% \n| style="text-align:center; font-weight:bold;" | ' .. format_pok(calc_pok(tot_g, tot_u)))
table.insert(html, table.concat(t_row, "\n"))
-- РЕЖИМ 2: РЕЗУЛЬТАТЫ УДАРОВ
elseif mode == "Результаты" then
table.insert(html, '|- \n! style="background-color:#e0f0ff;" | Место \n! style="background-color:#e0f0ff;" | Игрок \n! style="background-color:#e0f0ff;" | % \n! style="background-color:#e0f0ff;" | [[Лучший пенальтист#Система определения победителя|Показатель]] \n! style="background-color:#e0f0ff;" | Удары \n! style="background-color:#e0f0ff;" | Голы \n! style="background-color:#e0f0ff;" | вр. \n! style="background-color:#e0f0ff;" | в. \n! style="background-color:#e0f0ff;" | м. \n! style="background-color:#e0f0ff;" | шт. \n! style="background-color:#e0f0ff;" | п.')
local t_u, t_g, t_k, t_o, t_w, t_p, t_c = 0,0,0,0,0,0,0
for rank, p in ipairs(list) do
t_u = t_u + p.u; t_g = t_g + p.g; t_k = t_k + p.k; t_o = t_o + p.o; t_w = t_w + p.w; t_p = t_p + p.p; t_c = t_c + p.c
table.insert(html, '|- \n| style="text-align:center;" | ' .. rank .. ' \n| style="text-align:center; white-space:nowrap;" | [[' .. string.gsub(p.name, "_", " ") .. ']] \n| style="text-align:center;" | ' .. format_pct(p.g, p.u) .. ' \n| style="text-align:center; font-weight:bold;" | ' .. format_pok(p.pok) .. ' \n| style="text-align:center; font-weight:bold;" | ' .. p.u .. ' \n| style="text-align:center; font-weight:bold;" | ' .. p.g .. ' \n| style="text-align:center;" | ' .. p.k .. ' \n| style="text-align:center;" | ' .. p.o .. ' \n| style="text-align:center;" | ' .. p.w .. ' \n| style="text-align:center;" | ' .. p.p .. ' \n| style="text-align:center;" | ' .. p.c)
end
table.insert(html, '|- \n| colspan="2" style="text-align:center;" | \'\'\'ВСЕГО\'\'\' \n| style="text-align:center; font-weight:bold;" | ' .. format_pct(t_g, t_u) .. ' \n| style="text-align:center; font-weight:bold;" | ' .. format_pok(calc_pok(t_g, t_u)) .. ' \n| style="text-align:center; font-weight:bold;" | ' .. t_u .. ' \n| style="text-align:center; font-weight:bold;" | ' .. t_g .. ' \n| style="text-align:center; font-weight:bold;" | ' .. t_k .. ' \n| style="text-align:center; font-weight:bold;" | ' .. t_o .. ' \n| style="text-align:center; font-weight:bold;" | ' .. t_w .. ' \n| style="text-align:center; font-weight:bold;" | ' .. t_p .. ' \n| style="text-align:center; font-weight:bold;" | ' .. t_c)
end
table.insert(html, '|}')
return frame:preprocess(table.concat(html, "\n"))
end
-----------------------------------------------------------------------
-- МАГИЧЕСКАЯ ФУНКЦИЯ: Мега-трики Голов и Передач
-----------------------------------------------------------------------
function p.RenderMegaTricks(frame)
local mode = frame.args[1] or "Все" -- "Все", "2034", "Текст", "Сводка"
local stat_type = frame.args[2] or "Голы" -- "Голы" или "Передачи"
local ALL_YEARS
local db_key
local col_word_3, col_word_more
local has_6
if stat_type == "Передачи" then
ALL_YEARS = {"2026", "2030", "2034", "2038", "2042", "2046"}
db_key = "Мега%-трики_передач_Детали"
col_word_3 = "передачи"
col_word_more = "передач"
has_6 = false
else
ALL_YEARS = {"2006", "2010", "2014", "2018", "2022", "2026", "2030", "2034", "2038", "2042", "2046"}
db_key = "Мега%-трики_Детали"
col_word_3 = "гола"
col_word_more = "голов"
has_6 = true
end
local text_data = {
po_all = { [3]={}, [4]={}, [5]={}, [6]={} },
qf_plus = { [3]={}, [4]={}, [5]={}, [6]={} },
sf_plus = { [3]={}, [4]={}, [5]={}, [6]={} },
finals = { [3]={}, [4]={}, [5]={}, [6]={} }
}
-- 1. СБОР ИГРОКОВ И ИХ ДАННЫХ
local players_set = {}
for key, _ in pairs(data) do
local p_match = string.match(key, "^(.+)/" .. db_key)
if p_match then players_set[p_match] = true end
end
local list = {}
local table_totals = {g3=0, g4=0, g5=0, g6=0, tot=0, gr=0, po=0}
for player, _ in pairs(players_set) do
-- Точное имя ключа без экранирования для извлечения из data
local exact_key = (stat_type == "Передачи") and "Мега-трики_передач_Детали" or "Мега-трики_Детали"
local pdata = {name = player, total=0, g3=0, g4=0, g5=0, g6=0, po_tot=0, po3=0, po4=0, po5=0, po6=0, gr_tot=0, years={}}
for i, year in ipairs(ALL_YEARS) do
pdata.years[i] = {total = 0}
local str = data[player .. "/" .. exact_key .. "/" .. year]
if str and str ~= "" then
for stage, goals_str in mw.ustring.gmatch(str, "([ГВЧПТФ])(%d)") do
local g = tonumber(goals_str)
local is_po = (stage == 'В' or stage == 'Ч' or stage == 'П' or stage == 'Ф')
if mode == "Все" or mode == "Текст" or mode == "Сводка" or mode == year then
pdata.total = pdata.total + 1
pdata.years[i].total = pdata.years[i].total + 1
if g == 3 then pdata.g3 = pdata.g3 + 1
elseif g == 4 then pdata.g4 = pdata.g4 + 1
elseif g == 5 then pdata.g5 = pdata.g5 + 1
elseif g == 6 then pdata.g6 = pdata.g6 + 1 end
if is_po then
pdata.po_tot = pdata.po_tot + 1
if g == 3 then pdata.po3 = pdata.po3 + 1
elseif g == 4 then pdata.po4 = pdata.po4 + 1
elseif g == 5 then pdata.po5 = pdata.po5 + 1
elseif g == 6 then pdata.po6 = pdata.po6 + 1 end
else
pdata.gr_tot = pdata.gr_tot + 1
end
end
if mode == "Текст" then
if stage == 'Ф' then
table.insert(text_data.finals[g], {name = player, year = year})
end
if stage == 'Ф' or stage == 'П' then
text_data.sf_plus[g][player] = (text_data.sf_plus[g][player] or 0) + 1
end
if stage == 'Ф' or stage == 'П' or stage == 'Ч' then
text_data.qf_plus[g][player] = (text_data.qf_plus[g][player] or 0) + 1
end
if is_po then
text_data.po_all[g][player] = (text_data.po_all[g][player] or 0) + 1
end
end
end
end
end
if pdata.total > 0 then
table.insert(list, pdata)
table_totals.g3 = table_totals.g3 + pdata.g3
table_totals.g4 = table_totals.g4 + pdata.g4
table_totals.g5 = table_totals.g5 + pdata.g5
table_totals.g6 = table_totals.g6 + pdata.g6
table_totals.tot = table_totals.tot + pdata.total
table_totals.gr = table_totals.gr + pdata.gr_tot
table_totals.po = table_totals.po + pdata.po_tot
end
end
-- 2. ГЕНЕРАЦИЯ ОБЩЕЙ СВОДКИ (Режим "Сводка")
if mode == "Сводка" then
local function get_plural(n, form1, form2, form5)
local n10 = n % 10
local n100 = n % 100
if n10 == 1 and n100 ~= 11 then return form1 end
if n10 >= 2 and n10 <= 4 and (n100 < 10 or n100 >= 20) then return form2 end
return form5
end
local html = {}
if table_totals.g3 > 0 then table.insert(html, "* '''Хет-трик''' (3 " .. col_word_3 .. ") — " .. table_totals.g3 .. " " .. get_plural(table_totals.g3, "раз", "раза", "раз") .. ".") end
if table_totals.g4 > 0 then table.insert(html, "* '''Покер''' (4 " .. col_word_3 .. ") — " .. table_totals.g4 .. " " .. get_plural(table_totals.g4, "раз", "раза", "раз") .. ".") end
if table_totals.g5 > 0 then table.insert(html, "* '''Пента-трик''' (5 " .. col_word_more .. ") — " .. table_totals.g5 .. " " .. get_plural(table_totals.g5, "раз", "раза", "раз") .. ".") end
if has_6 and table_totals.g6 > 0 then table.insert(html, "* '''Гекса-трик''' (6 " .. col_word_more .. ") — " .. table_totals.g6 .. " " .. get_plural(table_totals.g6, "раз", "раза", "раз") .. ".") end
local players_count = #list
local action_word = (stat_type == "Передачи") and "отдать" or "оформить"
table.insert(html, "Как минимум один мега-трик в истории ЧТМ удалось " .. action_word .. " " .. players_count .. " " .. get_plural(players_count, "игроку", "игрокам", "игрокам") .. ".")
return frame:preprocess(table.concat(html, "\n"))
end
-- 3. ГЕНЕРАЦИЯ ТЕКСТА ПЛЕЙ-ОФФ (Режим "Текст")
if mode == "Текст" then
local function build_group(counts)
local rev, keys = {}, {}
local sum = 0
for p, c in pairs(counts) do
if not rev[c] then rev[c] = {}; table.insert(keys, c) end
table.insert(rev[c], p)
sum = sum + c
end
if sum == 0 then return 0, "" end
table.sort(keys, function(a,b) return a>b end)
local parts = {}
for _, c in ipairs(keys) do
table.sort(rev[c])
local links = {}
for _, p in ipairs(rev[c]) do table.insert(links, "[[" .. string.gsub(p, "_", " ") .. "]]") end
local str = table.concat(links, ", ")
if c > 1 then str = str .. " (по " .. c .. ")"
elseif c == 1 and #keys > 1 then str = str .. " (по 1)" end
table.insert(parts, str)
end
return sum, table.concat(parts, ", ") .. "."
end
local function build_finals(arr)
if #arr == 0 then return 0, "" end
table.sort(arr, function(a, b)
if a.year ~= b.year then return tonumber(a.year) < tonumber(b.year) end
return a.name < b.name
end)
local parts = {}
for _, item in ipairs(arr) do
table.insert(parts, "* '''[[" .. string.gsub(item.name, "_", " ") .. "]]''' ([[Финал ЧТМ-" .. item.year .. "|" .. item.year .. "]])")
end
return #arr, table.concat(parts, "\n")
end
local function section(title, data_grp, is_fin)
local res = {"=== " .. title .. " ==="}
local labels = { [6]="Гекса-трики", [5]="Пента-трики", [4]="Покеры", [3]="Хет-трики" }
local start_g = has_6 and 6 or 5
for g = start_g, 3, -1 do
if is_fin then
local count, txt = build_finals(data_grp[g])
if count > 0 then table.insert(res, "'''" .. labels[g] .. " (" .. count .. "):'''\n" .. txt) end
else
local count, txt = build_group(data_grp[g])
if count > 0 then table.insert(res, "'''" .. labels[g] .. " (" .. count .. "):''' " .. txt) end
end
end
-- Если секция пуста (только заголовок), возвращаем пустую строку
if #res == 1 then return "" end
return table.concat(res, "\n\n")
end
local text_html = {}
local s1 = section("Всего", text_data.po_all, false)
local s2 = section("В четвертьфиналах и позже", text_data.qf_plus, false)
local s3 = section("В полуфиналах и позже", text_data.sf_plus, false)
local s4 = section("В финалах", text_data.finals, true)
if s1 ~= "" then table.insert(text_html, s1) end
if s2 ~= "" then table.insert(text_html, s2) end
if s3 ~= "" then table.insert(text_html, s3) end
if s4 ~= "" then table.insert(text_html, s4) end
if #text_html == 0 then return "''В плей-офф мега-триков пока не зафиксировано.''" end
return frame:preprocess(table.concat(text_html, "\n\n"))
end
-- 4. СУПЕР-СОРТИРОВКА ДЛЯ ТАБЛИЦ
table.sort(list, function(a, b)
if a.total ~= b.total then return a.total > b.total end
if has_6 and a.g6 ~= b.g6 then return a.g6 > b.g6 end
if a.g5 ~= b.g5 then return a.g5 > b.g5 end
if a.g4 ~= b.g4 then return a.g4 > b.g4 end
if a.g3 ~= b.g3 then return a.g3 > b.g3 end
if a.po_tot ~= b.po_tot then return a.po_tot > b.po_tot end
if has_6 and a.po6 ~= b.po6 then return a.po6 > b.po6 end
if a.po5 ~= b.po5 then return a.po5 > b.po5 end
if a.po4 ~= b.po4 then return a.po4 > b.po4 end
if a.po3 ~= b.po3 then return a.po3 > b.po3 end
if mode == "Все" then
local sA, sB = a.total, b.total
for i = #ALL_YEARS, 1, -1 do
sA = sA - a.years[i].total
sB = sB - b.years[i].total
if sA ~= sB then return sA > sB end
end
end
return a.name < b.name
end)
-- 5. ГЕНЕРАЦИЯ ТАБЛИЦЫ
local html = {}
table.insert(html, '{{ПШТ}}{{стиль столбцов}}')
table.insert(html, '{| border="1" cellspacing="1" cellpadding="1" class="article-table sortable ts-stickytableheader"')
local h = {'|- \n! style="background-color:#e0f0ff;" | Место \n! style="background-color:#e0f0ff;" | Игрок \n! style="background-color:#e0f0ff;" | 3 ' .. col_word_3 .. ' \n! style="background-color:#e0f0ff;" | 4 ' .. col_word_3 .. ' \n! style="background-color:#e0f0ff;" | 5 ' .. col_word_more}
if has_6 then table.insert(h, '! style="background-color:#e0f0ff;" | 6 ' .. col_word_more) end
table.insert(h, '! style="background-color:#e0f0ff;" | ВСЕГО \n! style="background-color:#e0f0ff;" | Группа/плей-офф')
table.insert(html, table.concat(h, " \n"))
for rank, p in ipairs(list) do
local row = {'|- \n| style="text-align:center;" | ' .. rank}
table.insert(row, '| style="text-align:center; white-space:nowrap;" | [[' .. string.gsub(p.name, "_", " ") .. ']]')
table.insert(row, '| style="text-align:center;" | ' .. p.g3)
table.insert(row, '| style="text-align:center;" | ' .. p.g4)
table.insert(row, '| style="text-align:center;" | ' .. p.g5)
if has_6 then table.insert(row, '| style="text-align:center;" | ' .. p.g6) end
table.insert(row, '| style="text-align:center; font-weight:bold;" | ' .. p.total)
table.insert(row, '| style="text-align:center;" | (' .. p.gr_tot .. '/' .. p.po_tot .. ')')
table.insert(html, table.concat(row, " \n"))
end
local t_row = {'|- \n| \n| style="text-align:center;" | \'\'\'ВСЕГО\'\'\' \n| style="text-align:center; font-weight:bold;" | ' .. table_totals.g3 .. ' \n| style="text-align:center; font-weight:bold;" | ' .. table_totals.g4 .. ' \n| style="text-align:center; font-weight:bold;" | ' .. table_totals.g5}
if has_6 then table.insert(t_row, '| style="text-align:center; font-weight:bold;" | ' .. table_totals.g6) end
table.insert(t_row, '| style="text-align:center; font-weight:bold;" | ' .. table_totals.tot .. ' \n| style="text-align:center; font-weight:bold;" | (' .. table_totals.gr .. '/' .. table_totals.po .. ')')
table.insert(html, table.concat(t_row, " \n"))
table.insert(html, '|}')
return frame:preprocess(table.concat(html, "\n"))
end
return p