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

Нет описания правки
Нет описания правки
 
(не показано 37 промежуточных версий 10 участников)
Строка 9: Строка 9:
-- =========================================================
-- =========================================================
-- Добавите сюда 2050 год — и он автоматически появится во всех таблицах на сайте.
-- Добавите сюда 2050 год — и он автоматически появится во всех таблицах на сайте.
-- Нужны два разных массива для двух разных БД.
-- Только годы финальных турниров ЧТМ (для Data/2006, Data/2010 и т. д.):
Config.years = {2006, 2010, 2014, 2018, 2022, 2026, 2030, 2034, 2038, 2042, 2046}
Config.years = {2006, 2010, 2014, 2018, 2022, 2026, 2030, 2034, 2038, 2042, 2046}
Config.is_latest_finished = false -- Флаг: завершён ли последний турнир в списке? (влияет на выдачу медалей)
Config.is_latest_finished = true -- Флаг: завершён ли последний ЧТМ в списке?
 
-- Все годы, в которые проходил хотя бы один любой турнир (для Data/Tournaments/2006 и т. д.):
Config.all_years = {2006, 2009, 2010, 2013, 2014, 2015, 2017, 2018, 2019, 2020, 2021,
2022, 2023, 2024, 2025, 2026, 2027, 2028, 2029, 2030, 2031, 2032,
2033, 2034, 2035, 2036, 2037, 2038, 2039, 2040, 2041, 2042, 2043,
2044, 2045, 2046, 2047, 2048}
Config.rating_year = 2046 -- до какого года подсчитывается актуальный рейтинг
Config.champions_teams = { -- быстрый список чемпионов, чтобы не шарить по всей БД каждый раз
                [2006] = "МОН", -- Монголия
                [2010] = "АФГ", -- Афганистан
                [2014] = "ДОМ", -- Доминика
                [2018] = "МОН", -- Монголия
                [2022] = "МОН", -- Монголия
                [2026] = "ДОМ", -- Доминика
                [2030] = "СЕН", -- Сент-Люсия
                [2034] = "ГВА", -- Гваделупа
                [2038] = "КИР", -- Киргизия
                [2042] = "ИНД", -- Индия
                [2046] = "КИР", -- Киргизия
                -- Каждая команда имеет свой трёхбуквенный код, прописанный в Модуль:Data/Teams
}
Config.champions_players = {-- Все игроки всегда и везде проходят под одним и тем же именем,
-- например, Лёша и Лёха (или Диман и Диман Е., или Герыч и Геныч и т. д.) — это два разных человека,
-- данное правило для унификации соблюдается абсолютно всегда
                [2006] = {"Глеб", "Диман Е.", "Раф"},
                [2010] = {"Антон", "Апож", "Герыч", "Диман", "Ильич", "Крюча"},
                [2014] = {"Антон", "Артём", "Геныч", "Диман", "Олег"},
                [2018] = {"Андрей", "Артур", "Диман Е.", "Ильич", "Капуста", "Лёша", "Некит Х.", "Раф"},
                [2022] = {"Геныч", "Ильич", "Капуста", "Лёха", "Серёга", "Хвича"},
                [2026] = {"Антон", "Диман", "Ильич", "Лёха", "Макс", "Стас", "Эльнур"},
                [2030] = {"Антон", "Геныч", "Денис", "Макс", "Эльнур"},
                [2034] = {"Антон", "Бирюк", "Геныч", "Диман", "Макс", "Тимон"},
                [2038] = {"Алишер", "Антон", "Геныч", "Дима Кес.", "Лёха", "Макс"},
                [2042] = {"Геныч", "Диман", "Некит", "Ринат", "Серёга"},
                [2046] = {"Бирюк", "Геныч", "Диман", "Коля", "Серёга"},
}
 
-- =========================================================
-- 2. РУЧНОЙ КОНТРОЛЬ АКТИВНЫХ КОМАНД (КОСТЫЛЬ)
-- =========================================================
--[[
Сюда вписываются команды, которые продолжают выступления на текущем ЧТМ,
чтобы не писать сложнейшие алгоритмы для группового раунда
--]]
Config.active_teams_list = {}
 
-- Технический словарь для моментального поиска
Config.active_teams = {}
for _, t in ipairs(Config.active_teams_list) do
    Config.active_teams[t] = true
end


-- =========================================================
-- =========================================================
-- 2. ЕДИНЫЙ СТИЛЬ ВСЕХ ТАБЛИЦ (Дизайн)
-- 3. ЕДИНЫЙ СТИЛЬ ВСЕХ ТАБЛИЦ (Дизайн)
-- =========================================================
-- =========================================================


Строка 54: Строка 107:


-- =========================================================
-- =========================================================
-- 3. БЛОК ФИЛЬТРОВ (Белые списки стадий)
-- 4. БЛОК ФИЛЬТРОВ (Белые списки стадий)
-- =========================================================
-- =========================================================
-- Используется как хэш-таблица для мгновенного поиска O(1).  
-- Используется как хэш-таблица для мгновенного поиска O(1).  
Строка 67: Строка 120:


-- =========================================================
-- =========================================================
-- 4. БЛОК ЭПОХ (С какого года считается статистика)
-- 5. БЛОК ЭПОХ (С какого года считается статистика)
-- =========================================================
-- =========================================================
Config.eras = {
Config.eras = {
Строка 81: Строка 134:
     cards = 2038
     cards = 2038
}
}
--[[
Обычно все подсчёты идут именно с указанных годов.
Но есть одно важнейшее исключение:
Несмотря на эти цифры, абсолютно во всех финальных матчах
известны все составы и ассистенты. Как правило, в общую
статистику эти показатели не входят, но когда подсчитывается
что-то связанное именно с финалами или чемпионскими титулами,
то их тоже надо считать. Поэтому когда создаются алгоритмы подсчёта
для чего-то, связанного с финалами, то ни в коем случае не надо
связывать подсчёты с сыгранными матчами, иначе показатели финалов
с 2006 до 2018 не попадут в статистику.
--]]


-- =========================================================
-- =========================================================
-- 5. СЛОВАРЬ ПОКАЗАТЕЛЕЙ (Для генератора таблиц)
-- 6. СЛОВАРЬ ПОКАЗАТЕЛЕЙ (Для генератора таблиц)
-- =========================================================
-- =========================================================
-- ВСЕГДА ОБРАЩАЙ ВНИМАНИЕ НА adjustments!!!
-- ВСЕГДА ОБРАЩАЙ ВНИМАНИЕ НА adjustments!!!
Строка 105: Строка 170:


     ["own_goals"]          = { start = 2006, anti_prize = true, get_val = function(stats) return stats.own_goals end },
     ["own_goals"]          = { start = 2006, anti_prize = true, get_val = function(stats) return stats.own_goals end },
     ["head_goals"]         = { start = 2022, get_val = function(stats) return stats.goals.head end },
     ["head_goals"] = { -- не записывались в конкретных матчах на ЧТМ-2022 и ЧТМ-2026,
     ["heel_goals"]         = { start = 2026, get_val = function(stats) return stats.goals.heel end },
    -- а просто подсчитывались суммарно
        start = 2022,
        get_val = function(stats) return stats.goals.head end,
        adjustments = {
            players = {
                ["Диман"] = { [2022] = 3, [2026] = 4 },
                ["Антон"] = { [2026] = 1 },
                ["Макс"] = { [2026] = 1 },
            }
        }
    },
     ["heel_goals"] = { -- не записывались в конкретных матчах на ЧТМ-2026,
    -- а просто подсчитывались суммарно
        start = 2026,
        get_val = function(stats) return stats.goals.heel end,
        adjustments = {
            players = {
                ["Геныч"] = { [2026] = 2 },
                ["Макс"] = { [2026] = 1 },
                ["Серёга"] = { [2026] = 1 },
            }
        }
    },
     ["free_kick_goals"]    = { start = 2026, get_val = function(stats) return stats.goals.free_kick end },
     ["free_kick_goals"]    = { start = 2026, get_val = function(stats) return stats.goals.free_kick end },
     ["goalie_goals"]      = { start = 2022, get_val = function(stats) return stats.goals.goalie end },
     ["goalie_goals"]      = { start = 2022, get_val = function(stats) return stats.goals.goalie end },
Строка 117: Строка 204:
     },
     },
     ["assist_mega_tricks"] = { start = 2026, get_val = function(stats) return stats.assists.hat_trick + stats.assists.poker + stats.assists.penta end },
     ["assist_mega_tricks"] = { start = 2026, get_val = function(stats) return stats.assists.hat_trick + stats.assists.poker + stats.assists.penta end },
     ["clearances"]         = { start = 2022, get_val = function(stats) return stats.clearances end },
     ["clearances"] = { -- не записывались в конкретных матчах на ЧТМ-2022 и ЧТМ-2026
    -- а просто подсчитывались суммарно
        start = 2022,
        get_val = function(stats) return stats.clearances end,
        adjustments = {
            players = {
                ["Диман"] = { [2022] = 4, [2026] = 11 },
                ["Макс"] = { [2026] = 5 },
                ["Геныч"] = { [2026] = 2 },
                ["Антон"] = { [2026] = 1 },
                ["Ринат"] = { [2026] = 1 },
                ["Диман Е."] = { [2026] = 1 },
                ["Эльнур"] = { [2026] = 1 },
            }
        }
    },
     ["yellow_cards"]      = { start = 2038, anti_prize = true, get_val = function(stats) return stats.cards.yellow end },
     ["yellow_cards"]      = { start = 2038, anti_prize = true, get_val = function(stats) return stats.cards.yellow end },
     ["red_cards"]          = { start = 2038, anti_prize = true, get_val = function(stats) return stats.cards.red end },
     ["red_cards"]          = { start = 2038, anti_prize = true, get_val = function(stats) return stats.cards.red end },
Строка 128: Строка 230:
     ["pens_saved"]        = { start = 2006, get_val = function(stats) return stats.penalties.saved_as_goalie end },
     ["pens_saved"]        = { start = 2006, get_val = function(stats) return stats.penalties.saved_as_goalie end },
     ["caused_pens"]        = { start = 2026, anti_prize = true, get_val = function(stats) return stats.penalties.caused_pens end },
     ["caused_pens"]        = { start = 2026, anti_prize = true, get_val = function(stats) return stats.penalties.caused_pens end },
   
     ["clean_sheets"] = { -- статистика до ЧТМ-2022 не велась, 8 матчей из 14 восстановлены по косвенным точечным признакам
     ["clean_sheets"]       = { start = 2006, get_val = function(stats) return stats.clean_sheets end },
        start = 2006,
     ["matches"]            = { start = 2022, no_medals = true, get_val = function(stats) return stats.matches_total or 0 end },
        get_val = function(stats) return stats.clean_sheets end,
     ["field_matches"]      = { start = 2022, no_medals = true, get_val = function(stats) return stats.matches_field or 0 end },
        adjustments = {
            totals = {
                ["total"] = 6 -- Это надо только к колонке "Всего" добавлять, потому что невозможно установить не только игроков, но даже турниры
            },
            players = {
                ["Диман"] = { [2006] = 2, [2010] = 1, [2014] = 1 },
                ["Макс"] = { [2006] = 1 },
                ["Крюча"] = { [2006] = 1 },
                ["Герыч"] = { [2010] = 1 },
                ["Диман Е."] = { [2014] = 1 },
            }
        }
    },
     ["matches"]            = { start = 2022, get_val = function(stats) return stats.matches_total or 0 end },
     ["field_matches"]      = { start = 2022, get_val = function(stats) return stats.matches_field or 0 end },
     ["plus_minus"]        = { start = 2022, anti_prize = true, get_val = function(stats) return stats.plus_minus end,
     ["plus_minus"]        = { start = 2022, anti_prize = true, get_val = function(stats) return stats.plus_minus end,
         adjustments = {
         adjustments = {
Строка 151: Строка 267:
     },
     },
      
      
     -- Средние показатели
     -- Средние показатели (берут данные из специально подготовленного Комбайном массива .avg, где эпохи уже отфильтрованы)
     ["avg_goals"]          = { start = 2022, is_average = true, get_val = function(stats) return { num = stats.goals and stats.goals.total or 0, den = stats.matches_field or 0 } end },
     ["avg_goals"]          = { start = 2022, is_average = true, get_val = function(stats) return { num = stats.avg and stats.avg.goals_num or 0, den = stats.avg and stats.avg.goals_den or 0 } end },
     ["avg_assists"]        = { start = 2026, is_average = true, get_val = function(stats) return { num = stats.assists and stats.assists.total or 0, den = stats.matches_field or 0 } end },
     ["avg_assists"]        = { start = 2026, is_average = true, get_val = function(stats) return { num = stats.avg and stats.avg.assists_num or 0, den = stats.avg and stats.avg.assists_den or 0 } end },
      
      
     -- Призы (собираются отдельно, но выводим через словарь)
     -- Призы (собираются отдельно, но выводим через словарь)
Строка 161: Строка 277:


-- =========================================================
-- =========================================================
-- 6. НАБОР ИНСТРУМЕНТОВ (Внутренние утилиты)
-- 7. НАБОР ИНСТРУМЕНТОВ (Внутренние утилиты)
-- =========================================================
-- =========================================================
Config.utils = {
Config.utils = {
Строка 213: Строка 329:
         if metric == "plus_minus" and val > 0 then return "+" .. tostring(val) end
         if metric == "plus_minus" and val > 0 then return "+" .. tostring(val) end
         return tostring(val)
         return tostring(val)
     end
     end,
   
    -- Защита от двойных точек, например, после "Диман Е.")
    smart_dot = function(str)
        if not str or str == "" then return "" end
        local text = str .. "."
        -- Если образовались ровно две точки на конце (буква + точка от инициала + наша точка), меняем на одну
        text = string.gsub(text, "([^%.])%.%.$", "%1.")
        return text
    end,
}
}


-- =========================================================
-- =========================================================
-- 7. УНИВЕРСАЛЬНЫЙ РАДАР (Сканер присутствия)
-- 8. УНИВЕРСАЛЬНЫЙ РАДАР (Сканер присутствия)
-- =========================================================
-- =========================================================


Строка 273: Строка 398:


-- =========================================================
-- =========================================================
-- 8. УМНАЯ СОРТИРОВКА (Универсальный тайбрейкер)
-- 9. УМНАЯ СОРТИРОВКА (Универсальный тайбрейкер)
-- =========================================================
-- =========================================================
-- Если у игроков равные показатели, эта функция сама пойдет по годам  
--[[
-- с конца (от 2046 к 2006) и рассудит, кто должен быть выше.
Сначала сравнивает общие показатели. Если они равны, идет по годам  
с конца (от новых к старым). Поощряет "исторический приоритет":
при равенстве выше ставится тот, кто достиг этого показателя раньше.
--]]
function Config.tiebreaker(a, b, valid_years, is_avg, sort_asc)
function Config.tiebreaker(a, b, valid_years, is_avg, sort_asc)
     if is_avg then
     if is_avg then
         local sumA_num, sumA_den = a.total_num, a.total_den
        -- 1. Сравниваем общие средние показатели
         local sumB_num, sumB_den = b.total_num, b.total_den
         local tA_val = a.total_den == 0 and 0 or (a.total_num / a.total_den)
         local tB_val = b.total_den == 0 and 0 or (b.total_num / b.total_den)
          
          
        local sA = string.format("%.2f", tA_val)
        local sB = string.format("%.2f", tB_val)
       
        if sA ~= sB then
            if sort_asc then return tonumber(sA) < tonumber(sB) end
            return tonumber(sA) > tonumber(sB)
        end
       
        -- 2. Тайбрейкер по годам (с конца)
         for i = #valid_years, 1, -1 do
         for i = #valid_years, 1, -1 do
             local y = valid_years[i]
             local y = valid_years[i]
             sumA_num = sumA_num - (a.years[y] and a.years[y].num or 0)
             local yA_num = a.years[y] and a.years[y].num or 0
             sumA_den = sumA_den - (a.years[y] and a.years[y].den or 0)
             local yA_den = a.years[y] and a.years[y].den or 0
             sumB_num = sumB_num - (b.years[y] and b.years[y].num or 0)
             local yB_num = b.years[y] and b.years[y].num or 0
             sumB_den = sumB_den - (b.years[y] and b.years[y].den or 0)
             local yB_den = b.years[y] and b.years[y].den or 0
           
            local yA_val = yA_den == 0 and 0 or (yA_num / yA_den)
            local yB_val = yB_den == 0 and 0 or (yB_num / yB_den)
              
              
             local tA = string.format("%.2f", sumA_den == 0 and 0 or (sumA_num / sumA_den))
             local syA = string.format("%.2f", yA_val)
             local tB = string.format("%.2f", sumB_den == 0 and 0 or (sumB_num / sumB_den))
             local syB = string.format("%.2f", yB_val)
              
              
             if tA ~= tB then
             if syA ~= syB then
                 if sort_asc then return tonumber(tA) < tonumber(tB) end
                -- ЗНАКИ ПЕРЕВЕРНУТЫ: меньше в новом году = больше в старых = выше в таблице
                 return tonumber(tA) > tonumber(tB)
                 if sort_asc then return tonumber(syA) > tonumber(syB) end
                 return tonumber(syA) < tonumber(syB)
             end
             end
         end
         end
     else
     else
         local sumA, sumB = a.total_val, b.total_val
         -- 1. Сравниваем абсолютные общие показатели (Grand Total)
        if a.total_val ~= b.total_val then
            if sort_asc then return a.total_val < b.total_val end
            return a.total_val > b.total_val
        end
       
        -- 2. Тайбрейкер по годам (с конца)
         for i = #valid_years, 1, -1 do
         for i = #valid_years, 1, -1 do
             local y = valid_years[i]
             local y = valid_years[i]
             sumA = sumA - (a.years[y] or 0)
             local valA = a.years[y] or 0
             sumB = sumB - (b.years[y] or 0)
             local valB = b.years[y] or 0
             if sumA ~= sumB then
           
                 if sort_asc then return sumA < sumB end
             if valA ~= valB then
                 return sumA > sumB
                -- ЗНАКИ ПЕРЕВЕРНУТЫ: меньше в новом году = больше в старых = выше в таблице
                 if sort_asc then return valA > valB end
                 return valA < valB
             end
             end
         end
         end
     end
     end
     return a.name < b.name -- Алфавитный порядок как последний аргумент
   
    -- 3. Алфавитный порядок как последний аргумент (если статистика идентична)
     return a.name < b.name  
end
end


-- =========================================================
-- =========================================================
-- 9. КОНСТРУКТОР ТАБЛИЦ (Table Builder)
-- 10. КОНСТРУКТОР ТАБЛИЦ (Table Builder)
-- =========================================================
-- =========================================================
--[[
В подавляющем большинстве случаев используется ровно два дизайна
таблиц — разный для несворачиваемых и сворачиваемых.
Если не указано иное, то все таблицы по умолчанию
должны лепиться по одному из этих двух шаблонов в зависимости от типа.
Иногда могут выключаться сортировка или плавающая шапка,
но это опционально и всегда оговаривается дополнительно.
--]]
Config.builder = {
Config.builder = {
     -- 1. Создает стандартную таблицу с плавающей шапкой
     -- 1. Создает стандартную таблицу с плавающей шапкой
Строка 423: Строка 583:


-- =========================================================
-- =========================================================
-- 10. РУЧНОЙ КОНТРОЛЬ АКТИВНЫХ КОМАНД (КОСТЫЛЬ)
-- 11. ЕЩЁ ИСКЛЮЧЕНИЯ
-- =========================================================
-- =========================================================
-- Сюда вписываются команды, которые продолжают выступления на текущем ЧТМ
--[[
Config.active_teams_list = {"ЧАД", "СЕН", "КИР", "ТУР"}  
Для реализации сложной логики, согласно которой Геныч
 
не получает 4 гола в матче за 3-е место в общую статистику,
-- Технический словарь для моментального поиска
но получает в зачёт голов за Киргизию и Башмак
Config.active_teams = {}
--]]
for _, t in ipairs(Config.active_teams_list) do
Config.award_adjustments = {
     Config.active_teams[t] = true
    -- [год] = { [тип_награды] = { ... } }
end
    [2022] = {
        goals = {
            -- [ключ "Игрок_Команда"] = {добавка к total, добавка к матчам, добавка к last_hist}
            ["Геныч_КИР"] = {
                total = 4,
                match_phantom = {t = 4, p = 0},
                last_hist = 29300
            }
        }
     }
}


-- =========================================================
-- =========================================================
-- ЗАДОЛБАВШИЕ ОШИБКИ
-- ЗАДОЛБАВШИЕ ОШИБКИ
-- =========================================================
-- =========================================================
-- 1
--[[
-- Пожалуйста, грузи готовые таблицы через return frame:preprocess(Config.styles.wiki_templates .. tostring(html)),
1
-- а не через return Config.styles.wiki_templates .. tostring(html),
Пожалуйста, грузи готовые таблицы через return frame:preprocess(Config.styles.wiki_templates .. tostring(html)),
-- а то <templatestyles src="Шаблон:Плавающая_шапка_таблицы/styles.css" /> сырым кодом вылезает прямо на странице.
а не через return Config.styles.wiki_templates .. tostring(html),
-- 2
а то <templatestyles src="Шаблон:Плавающая_шапка_таблицы/styles.css" /> сырым кодом вылезает прямо на странице.
-- Обзор конкретного кейса от Gemini, но эта проблема возникала  
2
-- уже не единожды при разных обстоятельствах, необходимо всегда обращать на это внимание:
Обзор конкретного кейса от Gemini, но эта проблема возникала  
-- "Голевые передачи: В локальной функции build_complex_aggregate (которая строит простые нумерованные списки)
уже не единожды при разных обстоятельствах, необходимо всегда обращать на это внимание:
-- автор пытался сделать тернарный оператор: local target = (award_type == "assists") and g.assist or g.scorer.
"Голевые передачи: В локальной функции build_complex_aggregate (которая строит простые нумерованные списки)
-- В Lua, если g.assist оказывался nil (то есть пас никто не отдал), условие соскальзывало дальше и записывало  
автор пытался сделать тернарный оператор: local target = (award_type == "assists") and g.assist or g.scorer.
-- в ассистенты автора гола (g.scorer). Из-за этого каждый гол без ассистента плюсовался автору как голевая передача!  
В Lua, если g.assist оказывался nil (то есть пас никто не отдал), условие соскальзывало дальше и записывало  
-- Заменил на классический if-else".
в ассистенты автора гола (g.scorer). Из-за этого каждый гол без ассистента плюсовался автору как голевая передача!  
-- 3
Заменил на классический if-else".
-- Scribunto работает на Lua 5.1
3
-- Не используй хреновины, которые появились только в Lua 5.2 и далее,
Scribunto работает на Lua 5.1.5
-- в частности оператор goto и метки (::continue::)
Не используй хреновины, которые появились только в Lua 5.2 и далее,
в частности оператор goto и метки (::continue::)
4
Пожалуйста, ВСЕГДА обращай внимание на то, что общее число голов/передач и призы лучшему бомбардиру (Золотой Башмак)
и лучшему ассистенту — это РАЗНЫЕ сущности. Общее число голов/передач тупо считается по общей сумме. А призы
бомбардирам и ассистентам раздаются по количеству голов/передач за одну конкретную команду со сложным
собственным тайбрейкером в случае равенства.
5
При загрузке из Модуль:Data/GrandStats.json
Вот что написал Gemini Pro:
"Ах, чёрт возьми! Прости, это классическая и очень коварная ловушка парсера MediaWiki, о которой я на секунду забыл,
когда наводил красоту в коде. Дело в том, что когда mw.text.jsonDecode разворачивает JSON, движок PHP
(на котором работает Вики) видит ключи вроде "2006". PHP автоматически и принудительно превращает любые ключи,
состоящие только из цифр, в числовые индексы (integers). В итоге, когда таблица возвращается в Lua,
ключом становится число 2006, а не строка "2006". В своей первой успешной версии я использовал двойную проверку
tab[year] or tab[tostring(year)], и это спасло ситуацию. Но в версии с медалями я решил «сделать код чище»,
принудительно переведя всё в строки (y_str = tostring(year)), и стал искать только по строкам.
Разумеется, Lua строк не нашёл, вернул nil, и все ячейки оказались пустыми."
--]]
 
-- ================================
-- КРАТКАЯ СПРАВКА
-- ================================
 
-- (надоело уже постоянно объяснять, лучше сразу прописать в конфиге, чтобы мозг не плавился от непонимания)
--[[
Чемпионат третьего мира (сокращённо ЧТМ) — футбольный турнир, организованный группой энтузиастов в микрорайоне Тулака города Волгограда летом 2006 года.
Начавшись как шутка, соревнование очень быстро разрослось до значительных масштабов, всего в него было вовлечено в разное время не менее ста человек.
Турниры проводились на протяжении 2006—2007 гг. (четыре) и 2011—2013 гг. (также четыре), девятый ЧТМ был начат в 2014 году,
после чего турнир был заморожен на пять с половиной лет. В период 2020—2023 годов соревнование было возобновлено, но игровые дни проходили крайне редко,
поэтому девятый турнир продолжался в общей сложности почти девять лет и был закончен только в апреле 2023 года.
Вскоре стартовал десятый ЧТМ, завершившийся в мае 2024 года, а в октябре был начат одиннадцатый турнир.
 
Ни для кого не является секретом, что в детстве и юношестве многие любители футбола часто создают воображаемые турниры,
представляя себя в роли лучших мастеров мира, играющих за различные реально существующие команды. Как правило,
соревнования эти довольно скоротечны, часто бывают незавершёнными и ограничиваются топ-уровнем (Лига Чемпионов, Чемпионат Мира).
 
Однажды родилась мысль — а почему бы не провести альтернативный чемпионат мира среди самых слабых команд планеты,
чтобы всевозможные «банановые республики» получили возможность побороться за мировую корону в матчах с себе подобными?
 
В чемпионате принимают участие команды, названные в честь реальных стран и территорий мира.
По раз и навсегда установленному критерию отбора страны с хорошо или хотя бы более-менее прилично развитым уровнем футбола принимать участие в ЧТМ не могут.
В турнире не имеют права выступать сборные, хотя бы один раз игравшие в настоящем чемпионате мира, а также команды, реально претендовавшие на это
(например, Бахрейн или Иордания, игравшие в стыковых матчах).
 
Также не допускаются к участию сборные, добивавшиеся каких-либо значимых успехов на чемпионатах своих конфедераций
(например, Судан, дважды в далёкие времена бравший серебро на Кубке Африки). Но из этого правила бывают исключения.
О древних достижениях некоторых команд (Эфиопия, Мьянма) на момент их включения в ЧТМ организаторы соревнований в силу
своих на тот момент недостаточно глубоких познаний ещё не знали, а, скажем, выход Гваделупы в полуфинал Золотого Кубка-2007
и Буркина-Фасо в финал Кубка Африки-2013 произошли уже после их включения в ЧТМ. В этих случаях членство таких команд в федерации не пересматривалось.
 
Турниры проводятся по схеме, идентичной настоящему чемпионату мира. Финальному раунду предшествует отборочный.
Иногда он полностью или частично играется на самом деле, иногда — просто расписывается. Финальный раунд всегда играется полностью от начала до конца.
В нём участвуют 32 команды (кроме ЧТМ-2010, когда участников было 24), разделённые на 8 групп, по две команды из каждой группы выходят в плей-офф, где по системе на вылет определяют чемпиона.
 
Разумеется, набрать такое количество человек, чтобы полностью сформировать составы всех 32 команд, просто невозможно. Поэтому в ходе турнира все играют за разные сборные.
Перед каждым матчем проводится процедура определения составов. Каждый волен выбрать команду, за которую будет играть в конкретном матче.
Часто случаются численные перевесы среди желающих, в этих случаях часть составов определяется искусственным образом.
 
На первом ЧТМ и в начале отбора ко второму сила команд не регламентировалась, всё определялось случайным образом.
Но довольно быстро составы команд стали формировать, учитывая силу соперников, для чего была введена система рейтинга.
Чем ближе оппоненты находятся друг к другу в рейтинге, тем более равными формируются их составы. И наоборот, чем больше разница рейтинга,
тем сильнее должна быть разница в уровне игроков каждой из команд, вплоть до численного перевеса.
 
Разумеется, очень быстро у основных игроков сложились как свои симпатии, так и антипатии. Особенным шиком считается суперчемпионство:
не просто стать чемпионом третьего мира, то есть выиграть финальный матч, но сделать это в составе команды,
которую ты тащил к триумфу на протяжении всего турнира (а то и многих турниров). Такое удавалось Диману (за Доминику-2014 и 2026, а также Индию-2042),
Рафу (Монголия-2006 и 2018), Антону (Доминика-2014 и 2026), Генычу (Монголия-2022), Максу (Доминика-2026), Серёге (Индия-2042) и Ринату (Индия-2042).
 
Остроту чемпионату придают именно соперничества между командами, симпатичными тем или иным игрокам. В основном общество расколото на два лагеря:
сторонников Монголии и сторонников Доминики, но существует также множество других противостояний, если и уступающих по масштабу Битве Титанов, то не так сильно.
 
Очень часто бывают случаи врыва массы игроков за команду, которой они совершенно не симпатизируют, только по причине того,
что она противостоит сборной из враждебного лагеря. Или чтобы отомстить команде, выбившей чьего-либо любимца в предыдущем раунде.
Или чтобы отомстить людям (группе людей) за вылет собственного фаворита путём выбивания из борьбы его собственного фаворита.
В общем, клубок противоречий постоянно запутывается до невозможности и иногда приводит к тому, что ни один из фаворитов до финала не доходит,
поскольку их постоянно выщёлкивают изо всех сил антифанаты. Такими были финалы 2010 и 2034, сюда же относится и чемпионство невразумительной Сент-Люсии на ЧТМ-2030.
 
Разночтения в датах объясняются очень просто. Первый ЧТМ состоялся в 2006 году и эта дата является реальной.
Чтобы не быть зависимыми от времени и одновременно придать чемпионатам сходство с проведением настоящего мундиаля,
было решено просто прибавлять четыре воображаемых года по мере проведения каждого следующего турнира.
По тому же принципу приписывались годы и к прочим соревнованиям. Никаких неудобств это никогда не создавало,
кроме того, что приходилось постоянно объяснять, почему это мы играем турнир, скажем, 2022 года, хотя на дворе только 2011-й.


ЧТМ Реальные даты
2006 июнь—июль 2006
2010 август 2006
2014 сентябрь—октябрь 2006
2018 июнь—август 2007
2022 май—июнь 2011
2026 август 2011
2030 май—август 2012
2034 апрель—июнь 2013
2038 июль 2014; январь 2020—апрель 2023
2042 август 2023 — май 2024
2046 октябрь 2024 — май 2026
--]]
return Config
return Config