Как стать автором
Обновить

Как желание поиграть в шахматы превратилось в написание своего движка. История и реализация

Время на прочтение15 мин
Количество просмотров12K
Всего голосов 22: ↑21 и ↓1+20
Комментарии19

Комментарии 19

Мои выводы основаны на полезной обзорной статье, собственном опыте написания минимакса (не для шахмат) и скромном опыте игры:

1. У вас не описана рокировка (потому что это движение одновременно короля и ладьи, из кода навскидку непонятно, как это должно работать)
2. Не хватает «взятия на проходе» для пешки.
3. Оценка веса позиции не учитывает мобильности фигур — с одной стороны, мало проку от зажатого со всех сторон ферзя (у которого большой вес), с другой стороны, проходная пешка может навести много суеты, когда протопает доску насквозь. Также неучет мобильности может, вероятно, привести к тому, что вашему движку можно будет поставить детский мат. Простейший способ учета мобильности — умножить вес фигуры на число возможных ходов.
4. Использование в крайней степени неэкономичного способа хранения данных лишит вашу программу преимущества в виде возможности хранить (да и перебирать — перекидывание нескольких бит в регистрах CPU на порядки быстрее ковыряния в мапе) больше состояний в памяти. С другой стороны, это может мотивировать на поиск более оптимальных эвристик для отсечения и более точных оценок для позиций. Может показаться интересной задача сделать код и читаемым и оптимальным по ресурсам одновременно.
Все ваши замечания справедливы, однако я перед собой и не ставил цели сразу написать полноценный движок.
1. Да, рокировка не описана, но можно сделать ещё одну реализацию интерфейса Turn, которая будет содержать всю необходимую информацию для рокировки (например, с какой ладьёй меняемся). В моём подходе все варианты рокировки должен возвращать движок, если рокировка возможна (король не двигался, ладья не двигалась, между ними нет других фигур и рокировка не поставит короля под мат).
2. В силу специфичности данного хода я даже не пытался его реализовать в первой итерации. Довольно легко избежать взятия на проходе, если знаешь про это правило. Однако это будет ещё одна реализация Turn.
3. Про мобильность интересное замечание. Приму к сведению.
4. Вы абсолютно правы, но я на это пошёл сознательно. Хотя бы потому что в основном все пишут про битовые поля, а других вариантов особо не предлагают. Хотелось продемонстрировать такую структуру данных, которая была бы максимально простой для понимания.
Есть прекрасный сайт www.chessprogramming.org — там очень много интересного на эту тему.
«Довольно легко избежать взятия на проходе, если знаешь про это правило» — это правило было придумано примерно тогда, когда появилось правило хода пешкой на две клетки вперёд, чтобы нельзя было запирать позицию. Это такое особое правило, и как правило взятие на проходе «допускают» вполне осознанно, и не стараются его избегать.
«король не двигался, ладья не двигалась, между ними нет других фигур и рокировка не поставит короля под мат»
— между ними нет других фигур
— поле, на котором стоит король, поле которое пересекает король и поле, на которое становится король — не атакуется вражескими фигурами.
Спасибо за ссылку, почитаю! Что касается рокировки, то даже не все именитые шахматисты соблюдали эти правила. То есть имеется некоторая вариативность в правилах.
Если мы говорим про классические шахматы, то вариативности никакой нет и не было. Если говорить о шахматах Фишера, где фигуры в начальной позиции случайным образом меняются местами, то там тоже всё хорошо. После рокировки король и ладья становятся на привычные в классических шахматах места.
Была одна забавная шахматная задача в 1972 году, которая привела к уточнению формулировки правил рокировки в шахматах, но, разумеется, никто этой неоднозначностью не пользовался.
Хех, даже не знал про вертикальную рокировку))
Была еще история о том, как шахматист на турнире сделал длинную рокировку при стоящем на своей исходной позиции ферзевом коне.
Когда ошеломленный соперник остановил часы и позвал судью, нарушитель предъявил тому последний «Шахматный кодекс», где черным по белому было написано «Ни одна фигура, кроме коня и ладьи при рокировке, не может перепрыгивать через другие фигуры.».
Судья, впрочем, принял решение быть верным духу, а не букве, и новатор был вынужден делать ход королем.
(Да, очевидно, в правилах рокировки не было указано требование отсутствия фигур между королем и ладьей.)
Поглядите книжку Корнилов «Программирование шахмат и других логических задач». Правда, там не всё есть. Впрочем, кое-что, чего там нет, я в своей статье расписал.
А чего именно нет в этой книге, если в двух словах?
Например, Late Move Reduction.
Для ладьи также будем генерить ходы в диапазоне 8 клеток, но с помощью метода generateDiagonalTurns()

Для слона все же
спасибо за внимательность! исправили)
Вы бы прежде чем писать, все же ознакомились бы с теорией игры. Королева это вам не слон плюс ладья, а 9 пунктов. Король между прочим тоже не бесконечность, а 4 пункта (да да, в эндшпиле он очень даже фигура). Это материальная оценка. Плюс есть оценка позиции. Вам уже написали про мобильность. Если закрытая позиция конь больше слона, в открытой наоборот. И т.д. и т.п.
Ах да, и еще «Прежде всего я установил несколько бесплатных и условно-бесплатных игр» — не занимайтесь ерундой, идите на chess.com. Там и уроки есть, и про фигуры объясняется ;)

1) chess.com bad, lichess good
2) материальная оценка не является объективной истинной. Stockfish использует PawnValueMg = 126, KnightValueMg = 781,
BishopValueMg = 825, RookValueMg = 1276,
QueenValueMg = 2538 (https://github.com/official-stockfish/Stockfish/blob/master/src/types.h#L182) как базу. И очень успешно использует, не знаю зачем автор условно бесплатные программы.

Возможно в статье это не совсем очевидно отражено, поэтому скажу ещё раз. Сначала мне просто захотелось поиграть в шахматы, а уже затем захотелось самому посмотреть, как можно реализовать простой движок. Если бы я изначально задавался целью написать полноценный движок, то да, я бы глубоко погружался в тему и начинал с изучения существующих аналогов.
Хорошая статья, понятно что правила в шахматах не так просты, чтобы их с наскоку реализовать. Но её ценность не в полноте, а в том что это хороший старт, например для учебных целей.
Лично я её так воспринимаю, а не как исчерпывающий движок.
Да, вы очень точно отразили цель этой статьи. Спасибо!
Про некоторые правила вы не обмолвились.
На счёт рокоровки и взятия на проходе уже писали.
Есть ещё про 3 повторяющиеся позиции (плюс там тоже есть свои хитрости с рокировкой) и про 50 ходов без взятия фигур, тогда можно объявить ничью.

И ещё:
Сперва пишется первая буква, обозначающая фигуру (для пешек букву не используем). Затем поле, с которого фигура совершает ход.

Поле НА которое фигура совершает ход, а поле с которого пишется иногда, если есть неопределённость (2 одинаковые фигуры могут сходить на одно поле).

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

По поводу нотации для записи ходов я сознательно выбрал более многословную запись, чтобы её легче было объяснить людям, которые вообще не знакомы с шахматными нотациями.

Про тесты интересная мысль, как и предыдущие. Спасибо, я принял к сведению! Возможно потом доработаю движок с учётом ваших предложений.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий