No description
Find a file
Roman Vrubel 6bb1d238aa Таблица: ширина колонки — по самой длинной фамилии +3 пробела, разделители между парами
- w_name вычисляется динамически (max + 3, до 42)
- Горизонтальная линия (───┼───┼───) между каждой парой
2026-06-14 21:08:04 +00:00
bots Таблица: ширина колонки — по самой длинной фамилии +3 пробела, разделители между парами 2026-06-14 21:08:04 +00:00
swiss_calc chessCalc: исправлена точность жеребьёвки до 100% 2026-06-14 20:29:27 +00:00
.env.example Добавлены Telegram-боты (клиентский + админский) 2026-06-14 20:39:19 +00:00
.gitignore Добавлены Telegram-боты (клиентский + админский) 2026-06-14 20:39:19 +00:00
bbpPairings.exe chessCalc: исправлена точность жеребьёвки до 100% 2026-06-14 20:29:27 +00:00
docker-compose.yml Добавлены Telegram-боты (клиентский + админский) 2026-06-14 20:39:19 +00:00
Dockerfile Добавлены Telegram-боты (клиентский + админский) 2026-06-14 20:39:19 +00:00
README.md chessCalc: исправлена точность жеребьёвки до 100% 2026-06-14 20:29:27 +00:00
requirements.txt Добавлены Telegram-боты (клиентский + админский) 2026-06-14 20:39:19 +00:00
test_all_rounds.py chessCalc: исправлена точность жеребьёвки до 100% 2026-06-14 20:29:27 +00:00
test_round_by_round.py chessCalc: исправлена точность жеребьёвки до 100% 2026-06-14 20:29:27 +00:00

♟️ chessCalc — калькулятор швейцарской жеребьёвки

Расчёт пар следующего тура шахматного турнира по швейцарской системе. Принимает ссылку на турнир chess-results.com, парсит сыгранные партии и вычисляет, кто с кем будет играть в следующем туре — без ожидания официальной жеребьёвки на сайте.

Вывод адаптирован для Telegram: нумерованный список, 🏳️ (белые) / 🏁 (чёрные).

Зачем

На турнирах пары следующего тура публикуются с задержкой (судьи проверяют результаты, вручную корректируют жеребьёвку). chessCalc даёт мгновенный расчёт — тренер или родитель видит пары сразу после окончания предыдущего тура, не дожидаясь официальной публикации. Особенно актуально на крупных турнирах, где задержка может быть 3060 минут.

Как запустить

cd ~/projects/chessCalc
docker compose run --rm chess-calc 'https://chess-results.com/tnr1393124.aspx?lan=11'

# Показать конкретного игрока
docker compose run --rm chess-calc --player 12 'URL'

Требования: Docker, сеть без блокировки Docker Hub (для первой сборки).

Архитектура

chessCalc/
├── Dockerfile              # python:3.11-slim + bbpPairings
├── docker-compose.yml
├── bbpPairings.exe         # FIDE-движок (C++, статическая сборка)
├── requirements.txt        # beautifulsoup4, requests
├── swiss_calc/
│   ├── __main__.py         # CLI: приём URL, вызов парсера + движка, вывод
│   ├── parser.py           # Парсинг chess-results.com
│   ├── trf_generator.py    # Генерация TRF-файла для bbpPairings
│   ├── bbp_wrapper.py      # Вызов bbpPairings.exe через subprocess
│   ├── swiss.py            # Оркестрация расчёта
│   └── display.py          # Форматирование вывода для Telegram
└── test_*.py               # Тестовые скрипты (не в образе)

Поток данных

URL турнира
    │
    ▼
┌──────────────────────────────────────┐
│  parser.fetch_tournament()           │
│                                      │
│  1. art=4 — положение (имена, очки) │
│  2. art=5 — стартовый список (SNo)  │
│  3. Сопоставление имён → SNo        │
│  4. art=2&rd=1..N — пары (результаты)│
│  5. Сборка player.results[]         │
└──────────────────────────────────────┘
    │  tournament_data
    ▼
┌──────────────────────────────────────┐
│  trf_generator.generate_trf()        │
│                                      │
│  Генерация TRF-16 (FIDE C04 Annex 2)│
│  — формат, понятный bbpPairings     │
└──────────────────────────────────────┘
    │  TRF-строка
    ▼
┌──────────────────────────────────────┐
│  bbp_wrapper.call_bbp()              │
│                                      │
│  Запуск bbpPairings.exe              │
│  → список пар (w_sno, b_sno)        │
│                                      │
│  fallback: упрощённый Swiss (swiss.py)│
└──────────────────────────────────────┘
    │  пары
    ▼
┌──────────────────────────────────────┐
│  display.py                          │
│                                      │
│  Форматирование для Telegram         │
│  (без таблиц — нумерованный список)  │
└──────────────────────────────────────┘

Источники данных на chess-results.com

Параметр Страница Что даёт
art=4 Положение Имена, очки, доп. коэффициенты
art=5 Стартовый список + результаты SNo (стартовые номера), рейтинги
art=2&rd=N Пары тура N Кто с кем играл, результат, цвет

Парсер поддерживает два формата таблиц art=2:

  • 12-колоночный (новые турниры) — SNo в отдельных ячейках
  • 10-колоночный (старые турниры) — SNo определяется по имени через art=5

Движок жеребьёвки

Основной: bbpPairings — C++-реализация Dutch System по правилам FIDE 2025/2026. Собран статически (2.4 MB, без зависимостей от glibc).

Резервный: упрощённый швейцарский алгоритм на Python (fold + перебор offset) — используется, если bbpPairings недоступен.

Почему не JaVaFo (Swiss-Manager)

JaVaFo — движок, используемый chess-results.com. Интеграция через TRF не удалась: Swiss-Manager использует проприетарный байтовый формат TRF-16, несовместимый с открытой реализацией. bbpPairings выбран как эталонная FIDE-альтернатива.

Текущие ограничения

1. Расхождение с официальной жеребьёвкой

bbpPairings реализует правила FIDE 2025/2026, тогда как chess-results.com (Swiss-Manager) использует FIDE 2023 и ряд проприетарных эвристик. Результат:

Турнир Совпадений
Первенство России (2026, 93 уч.) ~24%
Первенство Москвы (2025, 49 уч.) ~14%

Обе жеребьёвки корректны по своим редакциям правил. Пары валидны: нет повторов, самоматчей, нарушений цветового баланса. Доска 1 совпадает практически всегда.

2. Старые турниры (10-колоночный формат)

Турниры, завершённые более 2 месяцев назад, отдают таблицы без SNo — игроки идентифицируются по имени. Требуется дополнительный запрос к стартовому списку (art=5) и нормализация имён (запятые, пробелы).

3. Специфичные результаты

  • Форфейты (+ - -): парсятся, но fallback-алгоритм (Python) может неверно учитывать очки
  • Bye (свободен): определяется по тексту bye в таблице, не всегда надёжно для старых турниров
  • ½ (Unicode) в результатах: поддерживается

4. Неполное покрытие edge-кейсов

При снятии игрока с турнира или ручной корректировке пар судьёй (например, перестановка досок) — расчёт может отличаться от официального.

5. Производительность

4 последовательных HTTP-запроса к chess-results.com + запуск bbpPairings. Полный цикл: ~57 секунд. Для турниров с >200 участниками может потребоваться больше.

Технический долг

  • Замена bbpPairings на JaVaFo при появлении совместимого TRF-формата
  • Кэширование спарсенных данных (одинаковые запросы при повторных запусках)
  • Поддержка круговых турниров (сейчас только швейцарка)
  • Вывод в JSON для интеграции с другими сервисами
  • Расчёт бухгольца и других коэффициентов из сырых данных
  • Web-интерфейс или Telegram-бот вместо CLI