- Основной интерфейс: Telegram-боты (клиентский + админский) - CLI оставлен для отладки - Архитектура дополнена bots/ и docker-compose сервисами - Точность: 4 из 5 турниров 100%, один 85% (ручные bye) - Актуализированы ограничения и техдолг
165 lines
9.5 KiB
Markdown
165 lines
9.5 KiB
Markdown
# ♟️ chessCalc — калькулятор швейцарской жеребьёвки
|
||
|
||
Расчёт пар следующего тура шахматного турнира **до официальной публикации**
|
||
на chess-results.com. Два Telegram-бота: клиентский принимает ссылку и
|
||
выдаёт пары в таблице, админский показывает статистику использования.
|
||
|
||
## Зачем
|
||
|
||
На турнирах пары следующего тура публикуются с задержкой (судьи проверяют
|
||
результаты, вручную корректируют жеребьёвку). chessCalc даёт мгновенный
|
||
расчёт — тренер или родитель видит пары сразу после окончания предыдущего
|
||
тура, не дожидаясь официальной публикации (30–60 минут).
|
||
|
||
## Как запустить
|
||
|
||
### Telegram-боты (основной способ)
|
||
|
||
```bash
|
||
cd chessCalc
|
||
|
||
# 1. Создать .env с токенами (см. .env.example)
|
||
cp .env.example .env
|
||
# Поправить токены в .env
|
||
|
||
# 2. Запустить обоих ботов
|
||
docker compose up -d
|
||
```
|
||
|
||
**Клиентский бот** — скинуть ссылку на турнир chess-results.com, получить
|
||
пары следующего тура в таблице (MarkdownV2).
|
||
|
||
**Админский бот** — команда `/stat`: уникальные пользователи, всего
|
||
запросов, запросов за сегодня.
|
||
|
||
### CLI (для отладки)
|
||
|
||
```bash
|
||
docker compose run --rm client-bot python3 -m swiss_calc 'URL'
|
||
|
||
# JSON-вывод
|
||
docker compose run --rm client-bot python3 -m swiss_calc --json 'URL'
|
||
|
||
# Положение после последнего тура
|
||
docker compose run --rm client-bot python3 -m swiss_calc --standings 'URL'
|
||
```
|
||
|
||
## Архитектура
|
||
|
||
```
|
||
chessCalc/
|
||
├── Dockerfile # python:3.11-slim + bbpPairings
|
||
├── docker-compose.yml # client-bot + admin-bot + volume bot-data
|
||
├── .env.example # шаблон токенов (коммитится)
|
||
├── .env # реальные токены (gitignored)
|
||
├── bbpPairings.exe # FIDE-движок (C++, статическая сборка)
|
||
├── requirements.txt # requests, bs4, python-telegram-bot, rich
|
||
├── swiss_calc/ # Ядро — парсинг + расчёт
|
||
│ ├── __main__.py # CLI entry point
|
||
│ ├── parser.py # Парсинг chess-results.com (art=2/4/5)
|
||
│ ├── trf_generator.py # Генерация TRF-16 для bbpPairings
|
||
│ ├── bbp_wrapper.py # Вызов bbpPairings.exe через subprocess
|
||
│ ├── swiss.py # Оркестрация + fallback Swiss-алгоритм
|
||
│ └── display.py # Форматирование вывода (CLI)
|
||
├── bots/ # Telegram-боты
|
||
│ ├── client_bot.py # Клиентский бот (ссылка → пары)
|
||
│ ├── admin_bot.py # Админский бот (/stat)
|
||
│ └── stats.py # Статистика (SQLite)
|
||
└── test_*.py # Тестовые скрипты
|
||
```
|
||
|
||
### Поток данных
|
||
|
||
```
|
||
Telegram-бот CLI (отладка)
|
||
│ │
|
||
│ URL турнира │ URL турнира
|
||
▼ ▼
|
||
┌─────────────────────────────────────────────────────┐
|
||
│ parser.fetch_tournament() │
|
||
│ │
|
||
│ 1. art=4 — положение (имена, очки, тайбрейки) │
|
||
│ 2. art=5 — стартовый список (SNo, рейтинги, FED) │
|
||
│ 3. Сопоставление имён → SNo (fuzzy-мэтчинг) │
|
||
│ 4. art=2&rd=1..N — пары/результаты каждого тура │
|
||
│ 5. Сборка player.results[] из art=2 + forfeit/bye │
|
||
└─────────────────────────────────────────────────────┘
|
||
│ tournament_data
|
||
▼
|
||
┌─────────────────────────────────────────────────────┐
|
||
│ swiss.calculate_next_round() │
|
||
│ │
|
||
│ 1. Генерация TRF-16 (trf_generator) │
|
||
│ 2. bbpPairings --dutch (FIDE 2025 Dutch System) │
|
||
│ → список пар (w_sno, b_sno) │
|
||
│ │
|
||
│ fallback: упрощённый Swiss (swiss.py) │
|
||
│ — если bbpPairings недоступен │
|
||
└─────────────────────────────────────────────────────┘
|
||
│ пары
|
||
▼
|
||
┌─────────────────────────────────────────────────────┐
|
||
│ Форматирование │
|
||
│ │
|
||
│ Telegram: MarkdownV2 + таблица в code-блоке │
|
||
│ CLI: нумерованный список │
|
||
└─────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### Источники данных на chess-results.com
|
||
|
||
| Параметр | Страница | Что даёт |
|
||
|----------|----------|----------|
|
||
| `art=4` | Положение | Имена, очки, тайбрейки |
|
||
| `art=5` | Стартовый список | SNo, рейтинги, федерации |
|
||
| `art=2&rd=N` | Пары тура N | Кто с кем играл, результат, цвет |
|
||
|
||
Парсер поддерживает два формата таблиц art=2:
|
||
- **12-колоночный** (новые турниры) — SNo в отдельных ячейках
|
||
- **10-колоночный** (старые турниры) — SNo определяется по имени через art=5
|
||
|
||
### Движок жеребьёвки
|
||
|
||
**Основной:** [bbpPairings](https://github.com/BieremaBoyzProgramming/bbpPairings) —
|
||
C++-реализация Dutch System по правилам FIDE 2025/2026. Собран статически
|
||
(2.4 MB, без зависимостей от glibc).
|
||
|
||
**Резервный:** упрощённый швейцарский алгоритм на Python (fold + перебор
|
||
offset) — bye-трекинг, абсолютные цвета, downfloat, форс-сведение.
|
||
|
||
## Точность
|
||
|
||
Проверено пошагово на 5 турнирах Первенства России (2026). Для каждого
|
||
тура 2..N: расчёт сравнивался с реальной жеребьёвкой с сайта.
|
||
|
||
| Турнир | Уч. | Формат | Точность |
|
||
|--------|-----|--------|----------|
|
||
| 1393121 | 39 | 12-кол. | **100%** |
|
||
| 1393124 | 93 | 12-кол. | **100%** |
|
||
| 1393133 | 96 | 12-кол. | **100%** |
|
||
| 1393137 | 14 | 12-кол. | **100%** |
|
||
| 1393131 | 112 | 12-кол. | **85%** |
|
||
|
||
**1393131 (85%)** — расхождения только в нижних досках. Причина: 4 ручных
|
||
bye/forfeit-а (игрок #8 снялся после 1-го тура, ещё трое получили bye).
|
||
Алгоритм не может предсказать снятие игрока — это решение арбитра.
|
||
|
||
На идущих турнирах без снятий — **100% совпадение**.
|
||
|
||
## Ограничения
|
||
|
||
1. **Ручные bye и forfeit-ы.** Если игрок снимается или получает bye
|
||
по решению арбитра (не по алгоритму) — жеребьёвка сдвигается.
|
||
Предсказать это невозможно.
|
||
2. **10-колоночный формат.** Старые турниры отдают таблицы без SNo —
|
||
игроки идентифицируются по имени. Точность ~80% из-за fuzzy-мэтчинга.
|
||
3. **Круговые турниры.** Не поддерживаются — только швейцарская система.
|
||
4. **Ручные корректировки судьи.** Перестановка досок, ручная цветовая
|
||
коррекция — алгоритм их не учитывает.
|
||
|
||
## Технический долг
|
||
|
||
- [ ] Поддержка круговых турниров
|
||
- [ ] Кэширование спарсенных данных
|
||
- [ ] Расчёт бухгольца и доп. коэффициентов из сырых данных
|
||
- [ ] Замена bbpPairings на JaVaFo при появлении совместимого TRF-формата
|