Шахматы голосом: как объяснить Алисе ход, если игрок не видит доску. Accessibility.. Accessibility. asr.. Accessibility. asr. python.. Accessibility. asr. python. stockfish.. Accessibility. asr. python. stockfish. Голосовые интерфейсы.. Accessibility. asr. python. stockfish. Голосовые интерфейсы. доступность.. Accessibility. asr. python. stockfish. Голосовые интерфейсы. доступность. интерфейсы.. Accessibility. asr. python. stockfish. Голосовые интерфейсы. доступность. интерфейсы. Разработка игр.. Accessibility. asr. python. stockfish. Голосовые интерфейсы. доступность. интерфейсы. Разработка игр. Тестирование игр.. Accessibility. asr. python. stockfish. Голосовые интерфейсы. доступность. интерфейсы. Разработка игр. Тестирование игр. шахматы.. Accessibility. asr. python. stockfish. Голосовые интерфейсы. доступность. интерфейсы. Разработка игр. Тестирование игр. шахматы. яндекс алиса.

Шахматы — почти идеальная игра для голосового интерфейса. Состояние компактное, ходов конечное число, правила формальны. Казалось бы, бери и делай.

На практике голосовой навык ломается не о шахматы, а о расшифровку речи. Игрок говорит «пешка е два е четыре», распознавание может вернуть «пешка е два и четыре». Для человека смысл очевиден; навык должен восстановить e2–e4 и при этом не угадывать, если позиция или качество разбора оставляют несколько вариантов.

Ниже — про то, как устроен навык «Шахматы с Юрой» для Яндекс Алисы и какие решения пришлось принять, чтобы игра оставалась играбельной на слух.

Ограничение, которое определило всё

Навык делался в первую очередь для незрячих и слабовидящих игроков. Из этого следует правило, которое пришлось соблюдать буквально везде: любое действие, нужное для партии, должно работать без экрана, и любой ответ должен звучать целиком.

Экранная карточка с доской есть, но она лишь дополняет ответ: ни одно обязательное действие не требует экрана, а позицию, историю и результат можно получить голосом. Это не про доступность как галочку в чек-листе — иначе продукт просто не работает для той аудитории, для которой он сделан.

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

Проблема 1: ASR не знает шахматной нотации

Распознавание речи обучено на обычном языке, а шахматная запись состоит из коротких похожих слогов. Названия вертикалей легко спутать; парсер учитывает, например, варианты «бэ», «пэ», «дэ» и склеенные координаты вроде «едва». Игроки также опускают предлог: «конь эф три» вместо «конь на эф три». Один и тот же ход можно правильно назвать несколькими способами.

Первая версия пыталась нормализовать фразу регулярками и надеяться на лучшее. Замеров я тогда не вёл, поэтому цифры не назову — но спор с ассистентом посреди партии случался достаточно часто, чтобы переписать этот слой целиком.

Рабочим оказался другой подход: текущая позиция служит словарём. Для каждого допустимого хода строятся возможные голосовые формы, а нормализованная фраза сопоставляется с ними. Один вариант с достаточной уверенностью — применяем ход. Несколько вариантов или низкая уверенность — переспрашиваем и не меняем доску. Если допустимого варианта нет, но фигуру и поля удалось восстановить, отдельно объясняем нарушенное правило; если намерение осталось неясным, просим уточнить.

Последний случай важнее, чем кажется. «Так нельзя» — бесполезный ответ, когда игрок не видит доску. Например, навык называет поле первой фигуры, закрывающей путь: «Путь закрыт: на поле e3 стоит пешка».

Проблема 2: движок не должен решать, что легально

Соблазн очевидный: Stockfish и так считает позицию, пусть он и скажет, законен ли ход. Так делать нельзя, и в проекте это записано отдельным инвариантом.

Stockfish — оптимизирующий поиск, а не арбитр правил. Он работает со своим представлением позиции, его вывод зависит от параметров поиска, и он вправе молчать при нехватке времени. Правила проверяет python-chess, детерминированно и без сети. Движок выбирает ответ соперника и используется в аналитических функциях: по запросу игрока, при разборе партии и для предупреждений тренера.

Разделение дало неожиданный бонус: тесты на правила не требуют движка вообще. Полный прогон шахматной логики идёт без единого процесса Stockfish.

Проблема 3: у ответа есть дедлайн 5 секунд

Алиса обрывает запрос через пять секунд. Не «показывает спиннер» — обрывает. Значит, весь путь «распознали → разобрали фразу → проверили правила → нашли ход → собрали речь» должен укладываться в бюджет с запасом.

Как это устроено:

  • общий бюджет ответа — 4,5 с; ожидание свободного процесса Stockfish вместе с поиском получает не более 3 с;

  • Stockfish живёт постоянно запущенным пулом процессов (по умолчанию два), каждый со своей блокировкой: запуск процесса на каждый ход не влезал в бюджет;

  • пул ограничен, и при исчерпании навык отвечает осмысленной фразой, а не встаёт в очередь до обрыва;

  • поиск уходит с event loop, чтобы не блокировать обработку.

Отдельная история — идемпотентность. Алиса повторяет запрос при сетевых сбоях, и повтор не должен приводить ко второму ходу. Каждый запрос несёт идентификатор, по которому распознаётся повтор, и повторный запрос получает тот же ответ, а не новую партию.

Проблема 4: позицию нужно уместить в человеческую память

Первая версия команды «какая позиция» читала всю доску одним ответом. Технически корректно. На слух — бесполезно: к четвёртой горизонтали первая уже забыта.

Сейчас доска читается по две горизонтали за раз, «дальше» продолжает чтение. Но чаще работает не полное чтение, а точечные вопросы: «что на е четыре», «где белые слоны», «чей ход», «есть ли шах», «какие фигуры съедены», «какой был последний ход», «что делали чёрные четыре хода назад».

Та же логика в справке: единый длинный список команд ухом не воспринимается, поэтому справка разбита на именованные разделы и читается страницами по три строки, с навигацией «дальше», «назад», «сначала».

Общий вывод, применимый к любому голосовому интерфейсу: ограничение — не время ответа, а объём, который удерживается в памяти без возможности перечитать.

Проблема 5: партия длиннее сессии

Голосовая сессия обрывается легко: колонку выключили, ушли из комнаты, Алиса переключилась на другой навык. Партия при этом не должна теряться.

Полное состояние партии хранится на сервере: каноничен список ходов UCI, FEN — производный снимок. В состоянии Алисы остаются идентификатор партии, ревизия и ограниченные данные текущего диалога — например, незавершённое уточнение и позиция в справке. Самой доски и полной истории там нет. Команда «продолжить последнюю партию» восстанавливает позицию с сервера и напоминает последние ходы.

Приватность: идентификатор, который нельзя развернуть

Исходный Alice ID в базу не попадает: до сохранения из него вычисляется псевдоним через HMAC-SHA256 с серверным секретом. Сырые webhook-запросы и аудио не сохраняются. Для улучшения распознавания навык до 30 дней хранит нормализованный текст команды и результат маршрутизации, связанные только с псевдонимом. Ключи запросов и сессий в служебной статистике хешируются, а публичная страница показывает лишь агрегированные счётчики и динамику по дням — без идентификаторов и текстов команд.

Открытая статистика проекта, который просит доверия у аудитории с повышенной чувствительностью к приватности, стоит дороже любого обещания в описании.

Что в итоге получилось

  • Полная партия против Stockfish, уровень сложности от 0 до 20, сохранение и продолжение.

  • Объяснение недопустимого хода конкретной причиной, когда понятен его замысел.

  • Голосовое описание позиции, истории, фактов о партии, дебюта и стадии.

  • Режим тренера: оценка позиции словами и числом, ходы-кандидаты, угрозы, подсказки от общего намёка до конкретного хода, разбор варианта без его исполнения.

  • Разбор сыгранной партии: перелом, главная ошибка, PGN, переигрывание позиции.

  • Голосовые задачи: мат в один и два хода, вилка, связка, сквозной удар.

  • Настройки речи, которые запоминаются между партиями.

Стек: Python 3.12, FastAPI, SQLAlchemy, MariaDB, python-chess, Stockfish. Модульный монолит, исходники открыты.

Попробовать: «Алиса, запусти навык Шахматы с Юрой». Сайт проекта: yurachess.ru. Про игру без экрана — отдельная страница, про тренировку вслепую — здесь. Код: github.com/Blaryxoff/yura-chess.

Что я сознательно не привожу: цифр точности распознавания. Корпус реальных фраз собирается с июля, но исторический результат показывает поведение той версии, которая работала в момент запроса. Чтобы честно назвать точность текущей версии, нужно повторно прогнать корпус через актуальный маршрутизатор и отдельно проверить выборку вручную. До такого замера процент был бы выдумкой.

Замечания и разборы кейсов, где навык говорит непонятно, — то, ради чего эта статья и написана.

Автор: blaryx

Источник