Калибровка параметров шахматного движка

—

от автора

Провокационное заявление: мой шахматный движок претендует превзойти по уровню и скорости все существующие. Конечно, с оговорками (об этом позже). Движок показывает прекрасные результаты, но в некоторых ситуациях необъяснимо терпит поражение. Чтобы исправить ситуацию, нужно анализировать большое количество данных (записи партий против программ-конкурентов), выявлять аномалии, вносить изменения в алгоритмы, подстраивать коэффициенты, запускать тестовые матчи и сравнивать результаты с прошлыми версиями. Анализ данных с помощью ИИ-чата показал сомнительную пользу: Claude упускает важные детали, выдвигает необоснованные предположения, советует неэффективные решения – работа замедляется и идёт по ложному следу.

Зато ИИ справился с написанием скриптов для управления программами-конкурентами: под чутким руководством научился выбирать уровень противника, распознавать позицию и последний сделанный ход, время на часах, признаки окончания партии. Причём, скрипты работают без обращения к самому ИИ и к Интернету (экономим токены).

Мой движок играет против приложения Chess.com

Мой движок играет против приложения Chess.com

Приложение Chess.com управляется только мышью. Claude забрал у меня курсор и не давал работать параллельно. Возникла мысль перенести всё это в виртуальную машину и подключить две мыши с раздельными драйверами, но на тот момент я посчитал это перебором. Поэтому матчи просто гонялись ночами, пока я спал.

Сеанс одновременной игры. Подсказка ↑ в каком смысле мой движок самый сильный

Сеанс одновременной игры. Подсказка ↑ в каком смысле мой движок самый сильный

Отчёты о первых партиях я смотрел прямо в Терминале в виде таблиц, которые печатал Claude. По ним быстро вскрылись некоторые проблемы движка (например, нехватка времени при игре на сильных уровнях, когда каждый ход обдумывался слишком долго). Но когда таблиц много, сверять их неудобно. А впереди нас ждали тысячи партий.

Статистически значимый результат получается только при многочисленных повторениях эксперимента, поэтому матчи состояли из 10-60 партий. Движок играл на одном и том же уровне сложности попеременно белым и чёрным цветом с одним и тем же противником. Статистика по каждой партии записывалась в csv-файл, в итоге получалась сводная таблица матча. Информация о каждом ходе в таблицу не попадала – вышло бы слишком много данных. Пока что надо было просто посмотреть на картину в целом и нащупать подходящие инструменты высокоуровнего анализа.

От таблиц к графикам

Данные матча я загрузил в Apple Numbers (аналог Microsoft Excel), добавил 4 столбца, приводящих данные к удобному для отображения виду, и построил график. Получилось именно то, что надо! Видна примерная сила игры движка на каждом из семи уровней, расход времени и аномальные партии (такие партии можно разобрать отдельно по логам).

Строю график в программе для электронных таблиц

Строю график в программе для электронных таблиц

Все любят дашборды

В этот момент я решил сконструировать собственный удобный инструмент для просмотра и сравнения данных. Выбрал такой стек: Claude мониторит партии, собирает статистику и записывает csv-файлы в директорию runs. Сервер написан на php, он читает файлы из runs и передаёт фронтенду. Там обычный html/css и по-минимуму JavaScript. На будущее была припасена идея ускорения: рисовать графики прямо в canvas. Но сперва нужно было определить сам вид графиков.

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

Понятно, что просто вывалить такое количество информации на пользователя нельзя. Но я решил доказать это от противного 🙂 Закинул в Claude Design csv-таблицу и график из Apple Numbers, подробно объяснил как такой график строить, описал вёрстку страницы и предложил Claude придумать как отобразить остальные данные. Конечно, я написал “сделай в стиле современных модных дашбордов”. Любой UX-дизайнер посмеётся над таким наивным заклинанием, но именно веселья мне и хотелось. Однако, получилось грустно:

Claude Design, что ты творишь?

Claude Design, что ты творишь?

Согласно моим критериям качества, это настолько плохой UX, что объяснять и исправлять что-либо бесполезно. Не найдя под рукой карандаша, я нарисовал грубый набросок в Figma. Да, выглядит некрасиво, но вполне годится в качестве иллюстрации к техническому заданию, которое я написал для Claude текстом.

Это набросок "на салфетке", а не дизайн!

Это набросок «на салфетке», а не дизайн!

По итогам двухдневной сессии с Claude Design получилось то, что надо. Слева направо на дашборде отображены 7 уровней сложности: на первом уровне движок думает поверхостно, а на седьмом размышления могут достигать максимальной глубины. Наведение на индикатор партии подсвечивает индикаторы в других блоках — это оказалось очень удобным. Нажатие на график приводит к его расширению. Сначала я сделал расширение по наведению мыши, но это оказалось слишком суетно. Автоматическое увеличение высоты я пока оставил – механизм помогает уместить больше информации на маленьких экранах.

Первая версия дашборда, полтора дня работы.

Первая версия дашборда, полтора дня работы.

Каждый проект требует индивидуального, оптимального в своём контексте способа отображения информации. Не существует “универсальных дашбордов” и “проверенных решений” – первые обитают в ученических работах на Behance и Dribbble, а вторые подходят лишь в тривиальных случаях. Так что для шахматного проекта я придумал два подходящих типа отображения информации.

Эти графики показывают изменение уровня сложности во времени по всем партиям матча. Полупрозрачные линии насыщают поле графика и таким образом выявляют тенденцию (если она есть). Конец партии обозначен резким обрывом линии вниз – благодаря этому возможно выделить курсором конкретную партию (её линия становится непрозрачной). С помощью этой визуализации удалось выявить и решить проблемы проигрыша по времени и падения качества игры при нехватке времени.

Круговая диаграмма показывает выделенный на данный уровень бюджет (максимальное количество позиций, которые разрешено просматривать движку на своём уровне сложности) – это серый диск. У разных уровней разный бюджет (можно посмотреть при наведении мыши), но отображение нормировано так, чтобы диски разных уровней имели одинаковый диаметр и символизировали 100% бюджета. Зелёный сектор показывает две величины: процент ходов, которые превысили бюджет (угол сектора) и на сколько процентов перерасходован бюджет (площадь сектора). Перерасход бюджета – это очень хорошо, несмотря на название: означает что программа думала во время хода противника, и успела обдумать больше, чем ей разрешено. Люди тоже так делают.

Помните, я говорил, что нельзя просто взять и вывалить на пользователя всю информацию? Красная часть круговой диаграммы показывает недорасход бюджета. Она находится точно на своём месте: серый сектор как раз соответствует ходам, которые не превысили бюджет. Заметный неизрасходованный бюджет может означать как “хорошо”, так и “плохо”. Ходы слабого противника были предугаданы и движку не пришлось тратить собственное время/бюджет – это хорошо. Партия затянулось, время поджимало, движку приходилось обрывать поиск, чтобы успеть сделать ход, бюджет не полностью потрачен – это плохо.

Вторая версия дашборда

Вторая версия дашборда

Крайние случаи, ошибки и пустые статусы

Наблюдаемых величин становилось больше и больше, а логи прошлых партий не содержали соответствующих записей, поэтому нужно было научиться работать с неполной информацией. Как только возник первый такой случай, принцип “нет информации – не отображаем блок” был применён ко всему проекту. Однако, в паре случаев недостающую информацию можно было восстановить приблизительно (например, предсказать падение уровня игры в зависимости от количества сделанных ходов и времени на часах). Заранее прорабатывать эти сценарии не имело смысла, потому что набор наблюдаемых величин не был зафиксирован. Проблемы решали по мере поступления. Ну а статусы типа “идёт загрузка” сделаны по-простому, так как дашборд запускается локально на компьютере с быстрым SSD. В конце концов, моей целью было создать инструмент за 2 дня.

Все же любят чат-ботов, нет?

Все же любят чат-ботов, нет?

На третий день я прикрутил к сайту чат-бота, чтобы можно было обсуждать с ним статистику и шахматы вообще. Обычно чат-боты тратят токены владельца сайта. Я придумал другой способ: пользователю предлагается подключить свой Claude или ChatGPT и чатиться за свой счёт. С Claude это работает даже на бесплатном тарифе. С ChatGPT сложней (можно сделать, но в данном случае получится over-engineering).

Компромиссы

Пока что нельзя погрузиться в подробности игры по ходам. Такое редко нужно, и можно обойтись просмотром логов. Если неохота читать логи – на дашборде есть чат-бот, у которого можно узнать все подробности о ходе партии. В будущем хочется добавить индикацию оценки каждого хода: как позицию оценивает движок, как её же оценивает Stockfish, каков материальный перевес. Эти величины похожи по смыслу, их можно отобразить на одном графике. Отдельный график – время, затраченное на ход и сводная гистограмма расхода времени (отдельно на дебют, миттельшпиль и ендшпиль, потому что движок ведёт себя немного по-разному в разные фазы игры).

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

Дашборд работает локально, и время загрузки данных ничтожно. Но я выложил онлайн-версию – там уже видна задержка: в сериях по 60 партий дашборд загружает 427 таблиц, и лишь потом рисует графики. В таких случаях у любого UI-дизайнера срабатывает рефлекс: надо добавить анимированную иконку загрузки. Я поступил иначе. Во-первых, оптимизировал отрисовку графики – там, где css и html вычисляли относительные величины типа процентов, но по факту значения были фиксированы, пересчитал их в пиксели. Профайлер браузера показал двукратное ускорение отрисовки. Во-вторых, собираюсь написать скрипт, который загружает данные партий в sql-базу, а не хранит файлами на диске – тогда чтение станет быстрей. И в-третьих, собираюсь читать данные из базы не скопом (420 партий), а постепенно, по одной партии для каждого уровня сложности – тогда можно рисовать графики по одному. Таким образом, поле графиков будет наполняться постепенно, по мере чтения данных – это и есть лучшая анимация загрузки! А главное, при работе с большими данными не обязательно дожидаться полной загрузки – можно начинать работать уже с тем, что загрузилось.

Что для меня сделал ИИ

Со времён Photoshop у меня есть привычка давать осмысленные названия всем объектам. В моей Figma никогда не встретишь “Frame 3754629”. Для совместной работы это исключительно важно. Теперь, в эпоху ИИ, привычка вкладывать смыслы в названия дала многократное ускорение: достаточно объединить текстовые строки Blitz, Rapid и Classical в auto-layout с названием “Tabs”, чтобы Claude понял какое оформление и поведение применить. Столбики и сектора диаграмм я назвал примерно так же, как колонки в таблице с данными, так что ИИ их связал, не задавая никаких вопросов.

Также Claude Design определил по моему Figma-наброску иерархию шрифтов и применил во всём проекте. Цвета инфографики правильно закрепились за соответствующими статистическими величинами. Мне не пришлось конструировать дизайн-систему – ясные названия элементов макета стали идеальными ответами на вопросы “как, что и почему”.

От себя Claude дорисовал горизонтальные отметки на графиках. С первого раза получилось симпатично. А вот с дополнительными цветами пришлось повозиться, вплоть до ручного вмешательства.

ИИ хорошо справился с заданием сделать тёмную тему, но стандарты контрастности (accessibility) провалил – об этом пришлось договариваться отдельно и выбирать из предложенных вариантов.

С первого раза получились иконки для светлой и тёмной темы. Остальные пришлось переделывать. Всё-таки, у нейросети по дефолту нет вкуса на такие вещи.

Конечно, Claude написал весь html, css, JavaScript и php. После просьбы поискать неиспользуемый, избыточный и медленный код ИИ уменьшил и ускорил своё творение вдвое.

Результат

В этом проекте я решал не только как отобразить данные, но и какие данные вообще показывать, каких данных не хватает для принятия решений, сбор какой информации нужно добавить в движок.

Дашборд помог выявить не только недостатки алгоритмов, но и откровенные баги (на аномальных партиях). Благодаря визуализации удалось настроить плавный рост сложности в зависимости от уровня. А главное, принять важные решения и внести изменения в продукт:

  • Добавился разогрев уровня: первые ходы обдумываются слабей, уровень повышается с каждым ходом, пока не достигнет заданного. Это решает две проблемы: UX (не заставляем пользователя долго ждать в начале партии) и таймаут (программа приберегает время на конец партии). Кстати, слишком быстрые ходы тоже не делаем – об этом ещё Стив Джобс говорил во время работы над первыми шахматами для Macintosh.

  • Понижение уровня: когда до конца партии остаётся мало времени, программа снижает уровень игры, чтобы не уронить флажок. Если удалось отодвинуть конец партии прибавкой времени за быстро сделанные ходы, уровень автоматически повышается. Это правило действует на уровнях 2-6.

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

  • Правило десяти секунд: перебор вариантов прерывается, если на часах осталось меньше 10 секунд. В этом случае исполняется лучший из найденных к этому времени ходов.

  • Отказ от идеи засчитывать обдумывание на ходу противника в бюджет (изначально половину потраченных ресурсов вычитали из общего бюджета, отведённого соответствующему уровню игры). Это не было похоже на игру с живым противником.

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

В следующей статье будет самое интересное: как я сконструировал и натренировал собственную нейросеть (можно сказать, LDM принятия решений). Для советского компьютера Электроника БК-0010 1984-го года.

ссылка на оригинал статьи https://habr.com/ru/articles/1095484/