Расследование ошибки в партии e7a94f8d-f7a6-11f0-bb4c-4725c2f0a926
Причина ошибки кроется в баге на стороне самого сервера dicechess.com, который пропустил запись одного из микро-ходов в историю, из-за чего наш движок валидации в аналитике посчитал ход нелегальным.
Ниже подробный разбор того, какой код за это отвечает и что произошло внутри данных.
1. Какой код отвечает за обработку и ошибку?
- Конвертация (Сборщик):
В репозитории
dicechess-syncфайл normalize.ts разбирает сыройgameMoveHistoryStateMapот сайта. Он берет ходы из поляgameMoveHistoryMoveкаждого узла состояния:} else if (move) { let uci = `${move.from.toLowerCase()}${move.to.toLowerCase()}`; if (move.promotion && move.promotion !== "NONE") uci += PROMO_TO_CHAR[move.promotion] ?? "q"; curMoves.push(uci); } - Валидация (Аналитика):
В репозитории
dicechess-analyticsфайл GameReplay.scala воспроизводит ходы через Scala-движок и сверяет их с легальными путями изTurnGenerator.- Правило максимального потребления кубиков (Maximum Micro-moves Rule): Движок требует, чтобы ход использовал максимальное количество доступных кубиков (в данном случае все 3). Если ход использует меньше кубиков, чем возможно, он считается нелегальным (
IllegalTurn).
- Правило максимального потребления кубиков (Maximum Micro-moves Rule): Движок требует, чтобы ход использовал максимальное количество доступных кубиков (в данном случае все 3). Если ход использует меньше кубиков, чем возможно, он считается нелегальным (
2. Что произошло в данных (Ход 17)
Давайте посмотрим на состояния в присланном вами файле 2026-06-25T183822.200.json на 17-м ходу (состояния 75, 76 и 77 в истории):
Шаг 75 (Начало хода черных)
- FEN:
rnk1r3/pppb1Npp/3P1p2/3p4/6n1/2Q5/PPPBP1PP/1R2KB1R b - - 2 1(Черные, на доске есть черный пешка наd5, белый ферзь наc3и черная ладья наe8). - Кубики:
[p, p, r](Пешка, Пешка, Ладья). - Ход:
null(просто бросок кубиков).
Шаг 76 (Первый микро-ход)
- Ход:
{ "from": "D5", "to": "D4" }(черная пешка ходитd5 -> d4). - FEN:
rnk1r3/pppb1Npp/3P1p2/8/3p2n1/2Q5/PPPBP1PP/1R2KB1R b - - 0 1(пешка теперь наd4, ферзь наc3). - Использован кубик: 1-я пешка (
p). Остались: пешка (p) и ладья (r).
Шаг 77 (Второй и третий микро-ходы — здесь баг сервера сайта)
- Ход:
{ "from": "E8", "to": "F8" }(черная ладья ходитe8 -> f8). - FEN:
rnk2r2/pppb1Npp/3P1p2/8/6n1/2p5/PPPBP1PP/1R2KB1R b - - 1 0 - Проблема: Посмотрите на изменения в FEN между шагом 76 и 77:
- Ладья переместилась с
e8наf8(согласно ходу). - Пешка с
d4переместилась наc3(взяв белого ферзя!).
- Ладья переместилась с
Сервер сайта обработал взятие ферзя пешкой (d4c3), изменил FEN, но забыл записать этот ход в массив gameMoveHistoryMove! Он сразу перепрыгнул на шаг 77, где записал только последний ход ладьей (e8f8), сохранив при этом результирующий FEN, где выполнены оба хода.
Результат парсинга:
Наш краулер собрал список ходов для этого хода: ["d5d4", "e8f8"] (взятие d4c3 потерялось, так как его не было в истории).
Результат валидации движком:
Движок видит кубики [p, p, r]. С этими кубиками у черных была возможность сделать три хода (включая взятие d4c3). Попытка сыграть только два хода ["d5d4", "e8f8"] нарушает правило максимального количества микро-ходов и отклоняется движком как нелегальная.
Как это выглядит на сайте?
На сайте игра выглядит нормально, потому что фронтенд сайта (или его внутренний парсер) восстанавливает ход d4xc3 динамически, сравнивая разницу FEN-ов между шагами, либо используя список ходов из другого внутреннего поля, недоступного в стандартном API истории шагов.
Что делать с этой ошибкой?
Поскольку эта ошибка вызвана битыми данными на сервере сайта, а не багом в нашем коде, у нас есть несколько путей:
- Просто пропустить эту партию (Рекомендуется):
В вашей базе данных из 63 985 партий только одна получила статус
rejected(это как разe7a94f8d...). Доля таких ошибок ничтожно мала (0.0015%). Проще всего оставить её в статусеrejected/skippedи не тратить ресурсы на усложнение парсера. - Написать костыль-обходчик в
normalize.ts: Мы можем добавить проверку конкретно для этогоgameId, и если это он — принудительно вставлять ходd4c3междуd5d4иe8f8. - Написать полноценный FEN-дефайлер: Анализировать разницу FEN между шагами истории и автоматически генерировать пропущенные ходы (сложно в реализации и тестировании из-за правил рокировок/превращений).