ЧТМ:Центр управления модулями/скрипт сбора статистики турниров

Материал из ЧТМ
Версия от 14:49, 30 мая 2026; LordBot (обсуждение | вклад) (Замена текста — «lang="py">» на «lang="python" line>»)
(разн.) ← Предыдущая версия | Текущая версия (разн.) | Следующая версия → (разн.)
Перейти к навигации Перейти к поиску
import re

# ==========================================
# 1. НАСТРОЙКИ ТУРНИРА
# ==========================================
TOURNAMENT = "ЧТМ" # Укажите название турнира
YEAR = "2046"      # Укажите год
IS_QUALIFICATION = True  # True = Квалификация (_Qual), False = Финальный турнир

# ==========================================
# 2. ВСТАВЬТЕ ВАШ ТЕКСТ ИЗ ВИКИПЕДИИ СЮДА
# ==========================================
DATA = """

"""

# ==========================================
# ДАЛЬШЕ НИЧЕГО НЕ ТРОГАЙТЕ
# ==========================================

ROUND_MAP = {
    "Предварительный раунд": "Qual",
    "Первый раунд": "1R",
    "Второй раунд": "2R",
    "Третий раунд": "3R",
    "Стыковые матчи": "Playoffs",
    "Дополнительный турнир": "AddTournament"
}

STAGE_MAP = {
    "Квалификация": "Qualification",
    "Первый тур": "Stage1",
    "Второй тур": "Stage2",
    "Третий тур": "Stage3",
    "1/16 финала": "16thfinal",
    "1/8 финала": "8thfinal",
    "1/4 финала": "Quarterfinal",
    "Четвертьфиналы": "Quarterfinal",
    "Четвертьфинал": "Quarterfinal",
    "Полуфиналы": "Semifinal",
    "Полуфинал": "Semifinal",
    "Финалы": "Final",
    "Финал": "Final"
}

CONFED_MAP = {
    "Южная Америка": "SouthAmerica",
    "Северная Америка": "NorthAmerica",
    "Америка": "America",
    "Евразия": "Eurasia",
    "Африка": "Africa",
    "Океания": "Oceania",
    "Европа": "Europe",
    "Азия": "Asia"
}
# Сортируем ключи по длине (по убыванию), чтобы Южная Америка проверялась раньше Америки
CONFED_KEYS = sorted(CONFED_MAP.keys(), key=len, reverse=True)

def parse_score(score_str, team1, team2, c1, c2, venue, is_second_leg=False):
    """Превращает счет из Вики-формата в формат Lua"""
    m = re.match(r'\s*(\d+):(\d+)(?:\(((?:ET|ЕT|пен\.)(?:(\d+):(\d+))?)\))?\s*', score_str)
    if not m:
        return None
    
    g1, g2 = m.group(1), m.group(2)
    spec = "nil"
    p1, p2 = "nil", "nil"
    
    if m.group(3):
        spec_text = m.group(3)
        if "ET" in spec_text or "ЕT" in spec_text:
            spec = '"aet"'
        elif "пен." in spec_text:
            spec = '"pen"'
            p1, p2 = m.group(4), m.group(5)

    if is_second_leg:
        return f'                {{"{team2}", "{team1}", {g2}, {g1}, {spec}, {p2}, {p1}, "{c2}", "{c1}", {venue}}}'
    else:
        return f'                {{"{team1}", "{team2}", {g1}, {g2}, {spec}, {p1}, {p2}, "{c1}", "{c2}", {venue}}}'

def main():
    lines = DATA.strip().split('\n')
    out = []
    
    tournament_key = f"{TOURNAMENT}_{YEAR}"
    if IS_QUALIFICATION:
        tournament_key += "_Qual"
        
    out.append(f'return {{\n    ["{tournament_key}"] = {{\n')

    current_round = ""
    current_stage = ""
    current_confed = ""
    
    is_add_matches = False
    is_neutral_global = False

    in_group = False
    in_knockout = False
    
    group_teams = []
    group_colors = []
    group_matrix = []
    group_type = "A2"
    knockout_matches = []

    def flush_group():
        if not group_teams: return
        key = f"{current_round}_{current_stage}".strip("_")
        if not current_round and current_stage: key = current_stage
        
        out.append(f'        ["{key}"] = {{')
        out.append('            type = "group",')
        if current_confed:
            out.append(f'            confederation = "{current_confed}",')
            
        out.append('            standings = {')
        for tm, col in zip(group_teams, group_colors):
            out.append(f'                {{"{tm}", "{col}"}},')
        out.append('            },')
        out.append('            matches = {')
        
        venue = 1 if group_type == "A2" and not is_neutral_global else 0
        num_teams = len(group_teams)
        
        for i, row in enumerate(group_matrix):
            col_idx = 0
            for j in range(num_teams):
                if i == j: continue
                if col_idx < len(row):
                    score = row[col_idx]
                    if ":" in score:
                        g1, g2 = score.split(":")
                        out.append(f'                {{"{group_teams[i]}", "{group_teams[j]}", {g1}, {g2}, {venue}}},')
                col_idx += 1
                
        out.append('            }\n        },')
        group_teams.clear(); group_colors.clear(); group_matrix.clear()

    def flush_knockout():
        if not knockout_matches: return
        key = f"{current_round}_{current_stage}".strip("_")
        if not current_round and current_stage: key = current_stage
        
        if is_add_matches and "AddMatches" not in key:
            key = f"{current_round}_AddMatches_{current_stage}"
            
        out.append(f'        ["{key}"] = {{')
        out.append('            type = "knockout",')
        if current_confed:
            out.append(f'            confederation = "{current_confed}",')
            
        out.append('            matches = {')
        for m in knockout_matches:
            out.append(m + ",")
        out.append('            }\n        },')
        knockout_matches.clear()

    for line in lines:
        line = line.strip()
        if not line: continue
        
        # Защита от прилипших скобок
        close_table_now = False
        if line.endswith("}}"):
            close_table_now = True
            line = line[:-2].strip()
            
        if not line and close_table_now:
            if in_group: flush_group()
            if in_knockout: flush_knockout()
            in_group = False
            in_knockout = False
            continue

        # Проверка нейтрального поля
        if "нейтральном поле" in line.lower() or "на нейтральном" in line.lower():
            is_neutral_global = True

        # СМЕНА РАУНДА
        m_round = re.match(r'===\s*(.+?)\s*===', line)
        if m_round:
            flush_group()
            flush_knockout()
            raw_round = m_round.group(1)
            current_round = ROUND_MAP.get(raw_round, "Round")
            is_add_matches = False
            current_confed = "" # Сбрасываем конфедерацию при новом раунде
            if current_round in ["Playoffs", "AddTournament", "Qual"]:
                current_stage = current_round
                current_round = ""
            continue

        # ПОИСК КОНФЕДЕРАЦИИ (только если мы не внутри таблицы)
        if not in_group and not in_knockout:
            for ck in CONFED_KEYS:
                if ck in line:
                    current_confed = CONFED_MAP[ck]
                    break  # Если нашли длинное имя (например Южная Америка), дальше не ищем

        if "; Дополнительные матчи" in line:
            is_add_matches = True
            continue

        # СМЕНА СТАДИИ / ГРУППЫ
        m_stage = re.match(r';:?\s*(.+)', line)
        if m_stage and "Дополнительные" not in m_stage.group(1):
            flush_group()
            flush_knockout()
            raw_stage = m_stage.group(1)
            
            if "Группа" in raw_stage:
                current_stage = raw_stage.replace("Группа ", "Group")
            else:
                current_stage = STAGE_MAP.get(raw_stage, raw_stage)
            continue

        # НАЧАЛО ТАБЛИЦЫ ГРУППЫ
        m_g_start = re.search(r'\{\{Группа\s*\d+-А(\d)', line)
        if m_g_start:
            in_group = True
            group_type = "A" + m_g_start.group(1)
            continue
            
        # НАЧАЛО ТАБЛИЦЫ ПЛЕЙ-ОФФ
        if re.search(r'\{\{И\d+', line):
            in_knockout = True
            continue

        # ПАРСИНГ СТРОКИ ГРУППЫ
        if in_group:
            m_row = re.match(r'^([A-Za-z]{1,2})\|([А-ЯЁ]{3})\|(.*?)\|*$', line)
            if m_row:
                color, team, scores_str = m_row.groups()
                group_colors.append(color)
                group_teams.append(team)
                scores = [s for s in scores_str.split('|') if s.strip() != '']
                group_matrix.append(scores)

        # ПАРСИНГ СТРОКИ ПЛЕЙ-ОФФ
        if in_knockout:
            m_ko = re.match(r'^\|?([A-Za-z]{1,2})\|([А-ЯЁ]{3})\|([^\|]+)\|([А-ЯЁ]{3})\|([A-Z-a-z]{1,2})', line)
            if m_ko:
                c1, t1, score_str, t2, c2 = m_ko.groups()
                venue = 0 if is_neutral_global else 1
                
                legs = [s.strip() for s in score_str.split(',')]
                for idx, leg in enumerate(legs):
                    is_second = (len(legs) == 2 and idx == 1)
                    parsed_leg = parse_score(leg, t1, t2, c1, c2, venue, is_second_leg=is_second)
                    if parsed_leg:
                        knockout_matches.append(parsed_leg)

        # КОНЕЦ ТАБЛИЦЫ (если скобки были прилипшими к последней строке)
        if close_table_now:
            if in_group: flush_group()
            if in_knockout: flush_knockout()
            in_group = False
            in_knockout = False

    # Сбрасываем всё, что осталось в самом конце
    flush_group()
    flush_knockout()

    out.append("    }\n}")

    result = "\n".join(out)
    print(result)

if __name__ == "__main__":
    main()