ChessCalcNextTour/swiss_calc/display.py
Roman Vrubel bbbfe61094 chessCalc: исправлена точность жеребьёвки до 100%
Основные изменения:
- swiss.py: переписан fallback-алгоритм (bye, downfloat, цвета, форс-сведение)
- trf_generator.py: генератор TRF-16 для bbpPairings
- bbp_wrapper.py: обёртка subprocess для bbpPairings.exe
- parser.py: полное переписывание парсера art=2/art=4/art=5
  - поддержка 10- и 12-колоночных форматов
  - пересборка результатов из art=2 для корректных SNo
  - финальный проход для forfeit/bye результатов
  - нормализация имён и fuzzy-мэтчинг
  - фикс пустых SNo-колонок
- __main__.py: починен JSON-вывод, поддержка bye
- display.py: отображение bye и источника расчёта

Ключевой фикс точности: убран XXC rank из TRF — bbpPairings
теперь использует порядок из турнирной таблицы вместо поля Rank.
Проверено на 5 турнирах (4 из 5 — 100%, 1 — 85% из-за ручных bye).
2026-06-14 20:29:27 +00:00

90 lines
2.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
Output formatting for Telegram Markdown.
"""
from .swiss import Player
def format_pairings_table(pairings_data: dict, tournament_name: str) -> str:
"""Format pairings as a Telegram-friendly markdown table.
Telegram auto-converts pipe tables to bullet lists, so we produce
clean formatted output that works well.
"""
pairings = pairings_data['pairings']
rnd = pairings_data['round']
lines = []
lines.append(f"**{tournament_name}**")
lines.append(f"📋 **Тур {rnd}** — пары")
lines.append("")
board = 1
for pairing in pairings:
if len(pairing) == 3:
p1, p2, color = pairing
if color == 'bye':
lines.append(f" {board}. {p1.name} — BYE (свободен)")
board += 1
continue
if color == 'w':
white, black = p1, p2
else:
white, black = p2, p1
elif len(pairing) == 5:
# raw tuple: (sno1, name1, color, sno2, name2)
sno1, name1, color, sno2, name2 = pairing
if color == 'w':
lines.append(f" {board}. {name1} 🏳️ — {name2}")
else:
lines.append(f" {board}. {name2} 🏳️ — {name1}")
board += 1
continue
else:
continue
w_name = white.name
b_name = black.name
w_pts = white.points
b_pts = black.points
w_rating = white.rating
b_rating = black.rating
pts_str = f" ({w_pts}/{b_pts})" if w_pts or b_pts else ""
rating_str = f"{w_rating}/{b_rating}" if w_rating or b_rating else ""
lines.append(f" {board}. {w_name} 🏳️ — {b_name}{pts_str}{rating_str}")
board += 1
lines.append("")
lines.append(f"Всего пар: {len(pairings)}")
if pairings_data.get('source') == 'bbp_pairings_fide_2025':
lines.append("_рассчитано по FIDE 2025 (bbpPairings)_")
elif pairings_data.get('source') == 'chess_results_precalculated':
lines.append("_пары с сайта chess-results.com_")
return '\n'.join(lines)
def format_player_standings(tournament_data: dict, top_n: int = 10) -> str:
"""Format top N players with their results."""
standings = tournament_data['standings'][:top_n]
if not standings:
return "Нет данных"
lines = []
lines.append(f"**{tournament_data['name']}**")
lines.append(f"📊 Положение после тура {tournament_data['current_round']}")
lines.append("")
for s in standings:
rank = s['rank']
name = s['name']
pts = s['points']
tb = s.get('tb', [])
tb_str = f" (Б: {tb[0]})" if tb else ""
lines.append(f" {rank}. {name} — **{pts}** очк{tb_str}")
return '\n'.join(lines)