Разработка новой рейтинговой системы (#22) #65

Merged
NotBigGhost merged 4 commits from issue-22-rating-proposal into dev 2026-09-14 21:44:21 +03:00
Collaborator

Что сделано

Документ docs/rating/rating-system.md описывает новую рейтинговую систему.

Модель — многопользовательский Elo: партия раскладывается на пары, ожидаемый исход считается из разницы рейтингов (треб. 3). Размер изменения масштабирует множитель отрыва:

  • темп победы относительно лимита раундов, с учётом хоумрула 9 раундов на 5–6 игроков (треб. 1);
  • отрыв по целям и мирам (треб. 4);
  • близость по типу победы (треб. 5);
  • вес размера стола — слабее, чем у темпа (треб. 2).

Шкала — классический Elo: старт 1500, D = 400, K новичка 64 → 16 у опытного. Пример «60 против 40» из задачи — это 1600 против 1400. Старая история пересчитывается по тем же формулам: у партий без новых полей признаки считаются нейтральными.

Скрипт docs/rating/simulate.py (только stdlib) — эталонная реализация. Он:

  • проверяет 15 пошаговых примеров документа через assert;
  • проверяет, что выбор шкалы не влияет на качество прогноза;
  • прогоняет синтетическую лигу в четырёх сценариях: сигнал, шум, клубы, рост.

Результат симуляции:

  • В сценариях, где отрыв связан с силой, предложенная система лучше текущего League Points и чистого Elo по всем метрикам качества. Например, ρ с истинной силой после 10 партий — 0.807 против 0.769, в «клубах» — 0.644 против 0.525.
  • В сценарии «шум» система уступает около 0.1 п.п. точности.

Доработка по замечаниям владельца

Замечания: уточнение в #22 и решения в этом PR.

  • Поле дуэли 2×3 (6 тайлов, 6.6 мира на игрока) — в таблице правил, скрипте, примерах 2 и 4 и симуляции. Пересчёт сдвинул метрики на тысячные, выводы не изменились.
  • Шкала 1500 — во всех формулах, примерах, пределах изменений и таблицах. Скрипт проверяет, что при этом точность, Brier и ρ совпадают с прежней шкалой до 1e-9. Меняются только сами числа рейтинга.
  • Раздел 8 (для #23):
    • правило last_standing ⇔ ровно один невыбывший: причина ставится автоматически и не выбирается вручную, сервер проверяет правило при завершении и правке;
    • бэкфилл истории для last_standing;
    • рейтинг показывается целым числом;
    • в общем топе убран столбец «Поб», «Очки» → «Рейтинг».
  • Раздел 9 «Открытые вопросы» стал «Решениями владельца»: все шесть пунктов и что из каждого следует.
  • Попутно: устаревший абзац про CLAUDE.md (которого нет в репозитории) заменён отсылкой к HelpPage.tsx, где формула продублирована; время прогонов в шапке исправлено на фактическое.

Коммиты

  • 8f1518b Рейтинг: эталонная реализация и симуляция новой системы
  • 648c10f Рейтинг: документ с предложением новой системы
  • af7d2b3 Рейтинг: поле 2×3 для дуэли и шкала 1500 в эталонной реализации
  • 28846c5 Рейтинг: документ по решениям владельца

Проверки

  • python docs/rating/simulate.py — exit 0 (≈1.5 мин): «Все примеры совпадают с документом» и «Шкала 1500 и шкала 50 дают одинаковые точность, Brier и ρ». Таблицы 7.3 взяты из этого прогона; повторный прогон финальной версии дал тот же вывод (плюс строка проверки шкалы).
  • python docs/rating/simulate.py --grid --grid-seasons 40 — exit 0 (≈7 мин), таблицы 7.4 взяты из этого прогона.
  • Поиск остатков старой шкалы и поля (2×2, D = 40, старт 50, K 6.4/1.6, +3.2) — только в тексте раздела 9, где описано решение.
  • git diff --stat origin/dev...HEAD — изменены только docs/rating/ (2 файла). Код приложения не затронут, тесты бэкенда и сборка фронта не нужны.
  • Формулы — блоки ```math, Gitea 1.27.3 их поддерживает.

Отклонения от плана

  • Добавлены сценарии «клубы» и «рост»: без них сравнение нечестно в пользу текущей системы.
  • Поправка на автокорреляцию проверена и не включена: её эффект около 0.0001 Brier.
  • Веса темпа и целей заданы требованиями, а не вершиной перебора (разделы 7.4 и 7.5).
  • В доработке: проверка инвариантности шкалы встроена в simulate.py, чтобы утверждение документа «формулы от шкалы не зависят» воспроизводилось, а не держалось на слове.

На утверждение

Открытых вопросов не осталось. Мёрж PR = утверждение предложения. После мёржа документ будет выложен комментарием в #23.

Closes #22

🤖 Generated with Claude Code

https://claude.ai/code/session_01LqSoRj99iwVEH5U5fnZgsd

## Что сделано Документ [`docs/rating/rating-system.md`](https://gitea.arseniev.info/NotBigGhost/ForbiddenStarsApp/src/branch/issue-22-rating-proposal/docs/rating/rating-system.md) описывает новую рейтинговую систему. **Модель** — многопользовательский Elo: партия раскладывается на пары, ожидаемый исход считается из разницы рейтингов (треб. 3). Размер изменения масштабирует множитель отрыва: - темп победы относительно лимита раундов, с учётом хоумрула 9 раундов на 5–6 игроков (треб. 1); - отрыв по целям и мирам (треб. 4); - близость по типу победы (треб. 5); - вес размера стола — слабее, чем у темпа (треб. 2). **Шкала** — классический Elo: старт 1500, D = 400, K новичка 64 → 16 у опытного. Пример «60 против 40» из задачи — это 1600 против 1400. Старая история пересчитывается по тем же формулам: у партий без новых полей признаки считаются нейтральными. **Скрипт** `docs/rating/simulate.py` (только stdlib) — эталонная реализация. Он: - проверяет 15 пошаговых примеров документа через `assert`; - проверяет, что выбор шкалы не влияет на качество прогноза; - прогоняет синтетическую лигу в четырёх сценариях: сигнал, шум, клубы, рост. **Результат симуляции:** - В сценариях, где отрыв связан с силой, предложенная система лучше текущего League Points и чистого Elo по всем метрикам качества. Например, ρ с истинной силой после 10 партий — 0.807 против 0.769, в «клубах» — 0.644 против 0.525. - В сценарии «шум» система уступает около 0.1 п.п. точности. ## Доработка по замечаниям владельца Замечания: [уточнение в #22](https://gitea.arseniev.info/NotBigGhost/ForbiddenStarsApp/issues/22#issuecomment-3380) и [решения в этом PR](https://gitea.arseniev.info/NotBigGhost/ForbiddenStarsApp/pulls/65#issuecomment-3466). - **Поле дуэли 2×3** (6 тайлов, 6.6 мира на игрока) — в таблице правил, скрипте, примерах 2 и 4 и симуляции. Пересчёт сдвинул метрики на тысячные, выводы не изменились. - **Шкала 1500** — во всех формулах, примерах, пределах изменений и таблицах. Скрипт проверяет, что при этом точность, Brier и ρ совпадают с прежней шкалой до 1e-9. Меняются только сами числа рейтинга. - **Раздел 8 (для #23):** - правило `last_standing` ⇔ ровно один невыбывший: причина ставится автоматически и не выбирается вручную, сервер проверяет правило при завершении и правке; - бэкфилл истории для `last_standing`; - рейтинг показывается целым числом; - в общем топе убран столбец «Поб», «Очки» → «Рейтинг». - **Раздел 9** «Открытые вопросы» стал «Решениями владельца»: все шесть пунктов и что из каждого следует. - Попутно: устаревший абзац про CLAUDE.md (которого нет в репозитории) заменён отсылкой к `HelpPage.tsx`, где формула продублирована; время прогонов в шапке исправлено на фактическое. ## Коммиты - `8f1518b` Рейтинг: эталонная реализация и симуляция новой системы - `648c10f` Рейтинг: документ с предложением новой системы - `af7d2b3` Рейтинг: поле 2×3 для дуэли и шкала 1500 в эталонной реализации - `28846c5` Рейтинг: документ по решениям владельца ## Проверки - `python docs/rating/simulate.py` — exit 0 (≈1.5 мин): «Все примеры совпадают с документом» и «Шкала 1500 и шкала 50 дают одинаковые точность, Brier и ρ». Таблицы 7.3 взяты из этого прогона; повторный прогон финальной версии дал тот же вывод (плюс строка проверки шкалы). - `python docs/rating/simulate.py --grid --grid-seasons 40` — exit 0 (≈7 мин), таблицы 7.4 взяты из этого прогона. - Поиск остатков старой шкалы и поля (`2×2`, `D = 40`, `старт 50`, K 6.4/1.6, `+3.2`) — только в тексте раздела 9, где описано решение. - `git diff --stat origin/dev...HEAD` — изменены только `docs/rating/` (2 файла). Код приложения не затронут, тесты бэкенда и сборка фронта не нужны. - Формулы — блоки ` ```math `, Gitea 1.27.3 их поддерживает. ## Отклонения от плана - Добавлены сценарии «клубы» и «рост»: без них сравнение нечестно в пользу текущей системы. - Поправка на автокорреляцию проверена и **не включена**: её эффект около 0.0001 Brier. - Веса темпа и целей заданы требованиями, а не вершиной перебора (разделы 7.4 и 7.5). - В доработке: проверка инвариантности шкалы встроена в `simulate.py`, чтобы утверждение документа «формулы от шкалы не зависят» воспроизводилось, а не держалось на слове. ## На утверждение Открытых вопросов не осталось. Мёрж PR = утверждение предложения. После мёржа документ будет выложен комментарием в #23. Closes #22 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01LqSoRj99iwVEH5U5fnZgsd
Agent added 2 commits 2026-09-13 19:52:36 +03:00
docs/rating/simulate.py — только stdlib, фиксированные seed. Содержит
многопользовательский Elo с множителем отрыва (темп, цели, миры, тип победы,
размер стола, K новичка) и пошаговые примеры документа с assert. Синтетическая
лига в сценариях «сигнал», «шум», «клубы» и «рост» сравнивает текущий League
Points, чистый Elo и предложенную систему. Флаг --grid перебирает K и веса
на отдельных сезонах. #22

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XfTsytzT6TojfmprRDKiV6
docs/rating/rating-system.md:
- проблемы текущего League Points;
- правила игры как исходные данные: тай-брейки, хоумрул 9 раундов, миры;
- выбор модели среди альтернатив, формулы и коэффициенты;
- трассировка требований 1–5 и пошаговые примеры;
- результаты симуляции и анализ чувствительности;
- последствия для реализации: поля, миграция, пересчёт истории, что
  ломается;
- открытые вопросы. #22

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XfTsytzT6TojfmprRDKiV6
Owner

Я налажал, когда расписывал количество систем, при игре вдвоём поле 2 на 3, а не 2 на 2.
Решение:

  1. Шкала - 1500. При реализации в интерфейсе, чтобы рейтинг поместился в столбец общего рейтинга приложения, нужно будет убрать столбец "количество побед". Заодно можно будет переименовать столбец из "очки" в "рейтинг"
  2. С коэффициентами типов побед согласен
  3. Такую причину победы добавить, в интерфейсе её реализовать так: если в партии все игроки, кроме одного, отправляются в поле "выбыл", автоматически проставить эту причину победы без возможности её заменить, пока в невыбывших игроках не будет хотя бы двоих. При этом в список выбора типа победы (выпадающее меню) его не добавлять
  4. ввод количества миров удобен, его оставляем
  5. затухание не добавляем
  6. минимум партий оставляем текущим (10)
Я налажал, когда расписывал количество систем, при игре вдвоём поле 2 на 3, а не 2 на 2. Решение: 1) Шкала - 1500. При реализации в интерфейсе, чтобы рейтинг поместился в столбец общего рейтинга приложения, нужно будет убрать столбец "количество побед". Заодно можно будет переименовать столбец из "очки" в "рейтинг" 2) С коэффициентами типов побед согласен 3) Такую причину победы добавить, в интерфейсе её реализовать так: если в партии все игроки, кроме одного, отправляются в поле "выбыл", автоматически проставить эту причину победы без возможности её заменить, пока в невыбывших игроках не будет хотя бы двоих. При этом в список выбора типа победы (выпадающее меню) его не добавлять 4) ввод количества миров удобен, его оставляем 5) затухание не добавляем 6) минимум партий оставляем текущим (10)
NotBigGhost added 2 commits 2026-09-14 21:11:34 +03:00
Решения владельца по #22: у дуэли поле 2×3 (6 тайлов, 6.6 мира на игрока),
шкала — классический Elo (R0 = 1500, D = 400, K 64 → 16; чистый Elo — 96 → 16).
Примеры и assert переведены в новую шкалу, сетки K в --grid умножены на 10,
|ΔR| League Points в сравнении приводится к шкале 1500. Добавлена проверка,
что шкала не влияет на точность, Brier и ρ. #22

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqSoRj99iwVEH5U5fnZgsd
Поле дуэли 2×3 в таблице правил и примерах; шкала 1500 в формулах, примерах
и пределах изменений; таблицы 7.3 и 7.4 — из новых прогонов simulate.py.
Раздел 8 для #23: правило last_standing (автоматически при одном невыбывшем,
проверка на сервере, бэкфилл истории), рейтинг целым числом, столбцы общего
топа; устаревший абзац про CLAUDE.md заменён отсылкой к HelpPage.tsx.
Раздел 9 «Открытые вопросы» стал «Решениями владельца». #22

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqSoRj99iwVEH5U5fnZgsd
NotBigGhost merged commit e40d93e7be into dev 2026-09-14 21:44:21 +03:00
NotBigGhost deleted branch issue-22-rating-proposal 2026-09-14 21:44:21 +03:00
Sign in to join this conversation.