⏱️ Корпус: длина партий, исходы и время
О чём это
Справочные измерения по всей базе (1 614 479 партий, замер 12.08.2026): сколько ходов живёт партия, чем она заканчивается, сколько партий падает по флагу на разных контролях. Это опорные числа для менеджера времени ботов, для дизайна анализа и для любых будущих решений про бюджеты. Прямое следствие уже заведено как engine#602.
Связанные: ml-lab-journal · game-analysis-design · database-structure
1. Длина партии
| ходов | |
|---|---|
| медиана | 12 |
| среднее | 14,7 |
| p90 | 27 |
| p99 | 49 |
| максимум | 574 |
Партии очень короткие. Хвост существует, но тонкий: длиннее 49 ходов лишь 1% партий. Это, кстати, ровно та причина, по которой explorer’ы и книга дебютов покрывают заметную долю реальной игры — глубина, на которую вообще успевает уйти партия, невелика.
Длина почти не зависит от контроля — на всех бэндах 13,7–15,0 ходов. То есть на длинных контролях игроки не играют дольше, они просто не тратят время.
2. Чем заканчиваются партии
| Исход | Партий | Доля |
|---|---|---|
king_captured | 1 434 405 | 88,85% |
timeout | 77 426 | 4,80% |
double_declined | 35 392 | 2,19% |
draw_agreement | 30 499 | 1,89% |
unknown | 22 639 | 1,40% |
resign | 14 120 | 0,87% |
Почти девять партий из десяти доигрываются до взятия короля — поэтому фильтр termination = king_captured для обучающих меток стоит так дёшево: он отсекает всего 11% корпуса (обоснование фильтра — в журнале, запись 09.08).
3. Проигрыши по времени — по контролям
| Контроль | Партий | Ср. ходов | Флаг |
|---|---|---|---|
| ≤ 60 с | 241 867 | 13,7 | 12,26% |
| 61–180 с | 573 894 | 14,9 | 4,68% |
| 181–300 с | 618 312 | 15,0 | 2,63% |
| > 300 с | 175 314 | 14,5 | 2,65% |
Ключевое наблюдение
С 300 секунд доля флагов перестаёт улучшаться: 2,63% против 2,65% на контролях свыше 300 с. Дополнительное время не расходуется — значит на контролях от трёх минут часы перестают быть ограничением. Это и есть измеренный запас, о котором стоит думать при проектировании бюджетов.
Самые популярные контроли: 300+5 (23,5% партий), 180+3 (16,6%), 60+1 (11,7%), 300+3 (8,7%).
4. Сколько ходов остаётся, если мы на ходу N
Условное ожидание по партиям с king_captured — то, что на самом деле нужно менеджеру времени:
| на ходу | партий живо | ожидается ещё | p90 ещё |
|---|---|---|---|
| 1 | 1 434 575 | 14,0 | 26 |
| 3 | 1 431 694 | 12,1 | 24 |
| 5 | 1 359 119 | 10,7 | 23 |
| 8 | 1 118 713 | 9,7 | 22 |
| 10 | 950 520 | 9,4 | 21 |
| 15 | 595 320 | 8,8 | 20 |
| 20 | 350 693 | 8,7 | 20 |
| 30 | 114 331 | 9,4 | 22 |
| 40 | 38 258 | 10,9 | 26 |
Две особенности этой кривой, и обе важны:
Она начинается с 14, а не с 30. Движковый TimeManager стартует с BaseMovesToGo = 30 — то есть на первом ходу делит часы примерно на вдвое большее число ходов, чем партия проживёт. Недоплата ложится на ранние ходы, где решается почти всё.
Гипотеза проверена — она верна, но не везде
Кривая переехала в движок как политика
empirical-v1(1.14.0) и стала дефолтом. Парный замер: +13 elo против линейного спада при KCP one-ply на 5+3 — разбор дуэли. Но приoracle-3с K=24 и K=48 политики неотличимы вовсе: дешёвый оценщик тратит 0.4 с при доступных 14–20 с, то есть часы там не связывают, ровно как и предсказывает раздел выше про исчерпание запаса с трёх минут. Выигрыш появляется только у дорогих оценщиков.
Она не монотонна. Проседает до 8,7 к 20-му ходу и снова растёт к 10,9 на 40-м: партия, дожившая до сорокового хода, по отбору является эндшпильной мельницей. Линейный taper не описывает ни начало кривой, ни её хвост — но именно хвост объясняет, почему потолок MaxFraction и резерв трогать нельзя.
5. Дырка в данных: thinking_time_ms пустая
Колонка turns.thinking_time_ms заполнена в 0 строк из 22 миллионов. При этом труба построена целиком: колонка в схеме есть, поле есть в контракте ingest (thinkingTimeMs: Option[Int]), IngestRepository его пишет — а производители шлют null. У play-api это даже записано явно в коде (.add("thinking_time_ms", Json.Null)), хотя часы он ведёт сам.
Поэтому фактический расход времени по ходам измерить сейчас нельзя — все выводы выше о запасе получены косвенно, через долю флагов. Заведено как play-api#316; исторические строки останутся NULL, данные никогда не существовали.
6. Косвенные подтверждения запаса со стороны ботов
- Timed-дуэль raw-board против oracle-3 (3+2, 7 400 партий): счётчики поражений по времени 0/0 на каждом промежуточном срезе.
- Книжная дуэль (3+2, 12 000 партий): тоже 0/0.
- Арифметика на 3+2: 180 с + 2 с × ~15 ходов ≈ 210 с на ~15 ходов ≈ ~14 с/ход доступно. Наши дешёвые оценщики тратят доли секунды; KCP-модель с K=48 — около 2,4 с/ход, то есть влезает с многократным запасом.
Как воспроизвести
Запросы — к прод-БД analytics (read-only), таблицы games и turns. Условное ожидание считается как avg(total_turns − N) по партиям с total_turns ≥ N при termination = 'king_captured'. Замер 12.08.2026 на 1 614 479 партиях; при существенном росте корпуса числа стоит пересчитать, но форма кривой вряд ли изменится — распределение устойчиво по контролям и по источникам.