ЧТМ:Центр управления модулями/скрипт сбора статистики турниров: различия между версиями
Перейти к навигации
Перейти к поиску
Burato (обсуждение | вклад) м Burato переименовал страницу ЧТМ:ЧТМ:Центр управления модулями/скрипт сбора статистики турниров в ЧТМ:Центр управления модулями/скрипт сбора статистики турниров без оставления перенаправления |
Burato (обсуждение | вклад) Нет описания правки |
||
| Строка 5: | Строка 5: | ||
# ========================================== | # ========================================== | ||
TOURNAMENT = "ЧТМ" # Укажите название турнира | TOURNAMENT = "ЧТМ" # Укажите название турнира | ||
YEAR = " | YEAR = "2046" # Укажите год | ||
IS_QUALIFICATION = True # True = Квалификация (_Qual), False = Финальный турнир | IS_QUALIFICATION = True # True = Квалификация (_Qual), False = Финальный турнир | ||
# ========================================== | # ========================================== | ||
# 2. ВСТАВЬТЕ ВАШ ТЕКСТ СЮДА | # 2. ВСТАВЬТЕ ВАШ ТЕКСТ ИЗ ВИКИПЕДИИ СЮДА | ||
# ========================================== | # ========================================== | ||
DATA = """ | DATA = """ | ||
| Строка 29: | Строка 29: | ||
STAGE_MAP = { | STAGE_MAP = { | ||
"Квалификация": "Qualification", | |||
"Первый тур": "Stage1", | "Первый тур": "Stage1", | ||
"Второй тур": "Stage2", | "Второй тур": "Stage2", | ||
| Строка 35: | Строка 36: | ||
"1/8 финала": "8thfinal", | "1/8 финала": "8thfinal", | ||
"1/4 финала": "Quarterfinal", | "1/4 финала": "Quarterfinal", | ||
"Четвертьфиналы": "Quarterfinal", | |||
"Четвертьфинал": "Quarterfinal", | |||
"Полуфиналы": "Semifinal", | "Полуфиналы": "Semifinal", | ||
"Полуфинал": "Semifinal", | "Полуфинал": "Semifinal", | ||
| Строка 40: | Строка 43: | ||
"Финал": "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): | def parse_score(score_str, team1, team2, c1, c2, venue, is_second_leg=False): | ||
| Строка 68: | Строка 84: | ||
out = [] | out = [] | ||
tournament_key = f"{TOURNAMENT}_{YEAR}" | tournament_key = f"{TOURNAMENT}_{YEAR}" | ||
if IS_QUALIFICATION: | if IS_QUALIFICATION: | ||
| Строка 77: | Строка 92: | ||
current_round = "" | current_round = "" | ||
current_stage = "" | current_stage = "" | ||
current_confed = "" | |||
is_add_matches = False | is_add_matches = False | ||
is_neutral_global = False | is_neutral_global = False | ||
| Строка 96: | Строка 113: | ||
out.append(f' ["{key}"] = {{') | out.append(f' ["{key}"] = {{') | ||
out.append(' type = "group",') | out.append(' type = "group",') | ||
if current_confed: | |||
out.append(f' confederation = "{current_confed}",') | |||
out.append(' standings = {') | out.append(' standings = {') | ||
for tm, col in zip(group_teams, group_colors): | for tm, col in zip(group_teams, group_colors): | ||
| Строка 129: | Строка 149: | ||
out.append(f' ["{key}"] = {{') | out.append(f' ["{key}"] = {{') | ||
out.append(' type = "knockout",') | out.append(' type = "knockout",') | ||
if current_confed: | |||
out.append(f' confederation = "{current_confed}",') | |||
out.append(' matches = {') | out.append(' matches = {') | ||
for m in knockout_matches: | for m in knockout_matches: | ||
| Строка 139: | Строка 162: | ||
if not line: continue | if not line: continue | ||
# | # Защита от прилипших скобок | ||
close_table_now = False | close_table_now = False | ||
if line.endswith("}}"): | if line.endswith("}}"): | ||
close_table_now = True | close_table_now = True | ||
line = line[:-2].strip() | line = line[:-2].strip() | ||
if not line and close_table_now: | if not line and close_table_now: | ||
if in_group: flush_group() | if in_group: flush_group() | ||
| Строка 153: | Строка 175: | ||
continue | continue | ||
# Проверка нейтрального поля | |||
if "нейтральном поле" in line.lower() or "на нейтральном" in line.lower(): | if "нейтральном поле" in line.lower() or "на нейтральном" in line.lower(): | ||
is_neutral_global = True | is_neutral_global = True | ||
# СМЕНА РАУНДА | |||
m_round = re.match(r'===\s*(.+?)\s*===', line) | m_round = re.match(r'===\s*(.+?)\s*===', line) | ||
if m_round: | if m_round: | ||
| Строка 163: | Строка 187: | ||
current_round = ROUND_MAP.get(raw_round, "Round") | current_round = ROUND_MAP.get(raw_round, "Round") | ||
is_add_matches = False | is_add_matches = False | ||
current_confed = "" # Сбрасываем конфедерацию при новом раунде | |||
if current_round in ["Playoffs", "AddTournament", "Qual"]: | if current_round in ["Playoffs", "AddTournament", "Qual"]: | ||
current_stage = current_round | current_stage = current_round | ||
current_round = "" | current_round = "" | ||
continue | 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: | if "; Дополнительные матчи" in line: | ||
| Строка 172: | Строка 204: | ||
continue | continue | ||
# СМЕНА СТАДИИ / ГРУППЫ | |||
m_stage = re.match(r';:?\s*(.+)', line) | m_stage = re.match(r';:?\s*(.+)', line) | ||
if m_stage and "Дополнительные" not in m_stage.group(1): | if m_stage and "Дополнительные" not in m_stage.group(1): | ||
| Строка 184: | Строка 217: | ||
continue | continue | ||
# НАЧАЛО ТАБЛИЦЫ ГРУППЫ | |||
m_g_start = re.search(r'\{\{Группа\s*\d+-А(\d)', line) | m_g_start = re.search(r'\{\{Группа\s*\d+-А(\d)', line) | ||
if m_g_start: | if m_g_start: | ||
| Строка 190: | Строка 224: | ||
continue | continue | ||
# НАЧАЛО ТАБЛИЦЫ ПЛЕЙ-ОФФ | |||
if re.search(r'\{\{И\d+', line): | if re.search(r'\{\{И\d+', line): | ||
in_knockout = True | in_knockout = True | ||
continue | continue | ||
# ПАРСИНГ СТРОКИ ГРУППЫ | |||
if in_group: | if in_group: | ||
m_row = re.match(r'^([A-Za-z]{1,2})\|([А-ЯЁ]{3})\|(.*?)\|*$', line) | m_row = re.match(r'^([A-Za-z]{1,2})\|([А-ЯЁ]{3})\|(.*?)\|*$', line) | ||
| Строка 203: | Строка 239: | ||
group_matrix.append(scores) | group_matrix.append(scores) | ||
# ПАРСИНГ СТРОКИ ПЛЕЙ-ОФФ | |||
if in_knockout: | if in_knockout: | ||
m_ko = re.match(r'^\|?([A-Za-z]{1,2})\|([А-ЯЁ]{3})\|([^\|]+)\|([А-ЯЁ]{3})\|([A-Z-a-z]{1,2})', line) | m_ko = re.match(r'^\|?([A-Za-z]{1,2})\|([А-ЯЁ]{3})\|([^\|]+)\|([А-ЯЁ]{3})\|([A-Z-a-z]{1,2})', line) | ||
| Строка 216: | Строка 253: | ||
knockout_matches.append(parsed_leg) | knockout_matches.append(parsed_leg) | ||
# | # КОНЕЦ ТАБЛИЦЫ (если скобки были прилипшими к последней строке) | ||
if close_table_now: | if close_table_now: | ||
if in_group: flush_group() | if in_group: flush_group() | ||
| Строка 233: | Строка 270: | ||
if __name__ == "__main__": | if __name__ == "__main__": | ||
main() | main()</syntaxhighlight> | ||
Версия от 03:52, 17 апреля 2026
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()