...

Как решить шахматную задачу с помощью компьютера

Создаем свой шахматный движок: алгоритм игры компьютера

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

В первой статье я начал с истории и поделился реализацией ходов. Было много по делу в комментариях, поэтому в планах движок продолжать улучшать. Не претендую на звание гроссмейстера, just for fun. Но, как и для любого программиста, нет предела совершенству 🙂

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

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

Все исходники проекта выложил на Github.

Задаем алгоритм игры компьютера

Создадим класс с очень амбициозным именем Ai и свойством color, который будет содержать цвет игрока-компьютера (чёрный или белый). Класс содержит единственный публичный метод nextTurn() . Этот метод принимает текущее состояние доски в виде фигур и возвращает объект Turn , который он считает наиболее оптимальным.

class Ai(private val color: PieceColor)

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

val pieces = HashMap(board.getPieces()) val currentSpacesUnderEnemyAttack = utils.getSpacesUnderAttack(pieces) .getValue(color.other())

Теперь запросим у движка все доступные ходы для каждой фигуры текущего игрока-компьютера и для каждого из них вычислим «профит» — числовую оценку успешности хода. Всю необходимую информацию сохраняем во вспомогательный data-класс TurnProfitInfo .

 val profits = board.getTurnsForColor(color) .entries.map < (from, turns) ->turns.map < turn ->TurnProfitInfo( from = from, turn = turn, profit = turn.getProfit(pieces, currentSpacesUnderEnemyAttack) ) > > .flatten()

Сама логика вычисления профита содержится в методе расширения Turn.getProfit() . После вычисления всех профитов найдем максимальный.

val maxOwnProfit = profits.maxOf

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

val turnPriceInfo = profits.filter < it.profit == maxOwnProfit >.shuffled() .first() return turnPriceInfo.turn >

Оценка хода, или какая фигура будет уничтожена

Теперь вернемся к методу getProfit() , который выполнен как расширение класса Turn . На вход он принимает текущее состояние доски и клетки, которые могут быть атакованы противником на следующем ходу.

private fun Turn.getProfit( pieces: HashMap, currentSpacesUnderEnemyAttack: Set ): Int < var profit = 0

Если в результате хода уничтожаем вражескую фигуру, то прибавляем ее стоимость к профиту. Затем делаем пробный ход.

this.enemyPiece?.let < profit += it.getPrice() >this.execute(pieces)

После выполнения хода определяем клетки, которые могут быть атакованы соперником:

val newSpacesUnderEnemyAttack = utils.getSpacesUnderAttack(pieces) .getValue(color.other())

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

if (this.from in currentSpacesUnderEnemyAttack && this.to !in newSpacesUnderEnemyAttack) < profit += this.sourcePiece.getPrice() >else if (this.from !in currentSpacesUnderEnemyAttack && this.to in newSpacesUnderEnemyAttack)

В конце отменяем пробный ход.

 this.revert(pieces) return profit >

В этом алгоритме ключевое влияние на профит оказывает возможность уничтожения вражеской фигуры и изменение «статуса атакованности» для той фигуры, которая выполняет ход. Стоимость фигуры зависит от типа и также влияет на итоговый профит.

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

Вместо заключения

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

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

Буду рад любой обратной связи и продолжать улучшать алгоритм, поэтому пишите свои вопросы и идеи в комментариях!

  • Блог компании Райффайзен Банк
  • Разработка игр
  • Kotlin
  • Научно-популярное
  • Логические игры

Как решить шахматную задачу с помощью компьютера

Открытые дебюты

  • Урок №16. Общие правила разыгрывания дебюта
  • Смотреть ещё

Полуоткрытые дебюты

Полуоткрытые дебюты

  • Урок №25. Сицилианская защита. Вариант Найдорфа
  • Смотреть ещё

Закрытые дебюты

Закрытые дебюты

  • Урок №100. Дебют ферзевых пешек. Система Колле
  • Смотреть ещё

Полузакрытые дебюты

Полузакрытые дебюты

  • Урок №106. Новоиндийская защита
  • Смотреть ещё

Фланговые дебюты

Фланговые дебюты

  • Урок №131. Дебют Рети
  • Смотреть ещё

+

  • Эндшпиль +
  • Играть
    • Играть с людьми
    • Белыми против компьютера
    • Чёрными против компьютера
    • Самостоятельная тренировка
    • Конструктор шахматных позиций
    • Шахматные задачи
    • Играть в пасьянс паук

    +

  • Информация
    • О нас
    • Написать нам
    • Наши акции
    • API для разработчиков
    • Франшиза
    • Работайте у нас!

    +

  • Интересное
    • Чемпионы мира
    • Шахматные курсы
    • Купить абонемент
    • Карлсен - Карякин (чемпионат мира 2016)
    • Блог
    • Наши партнёры

    +

    • Главная
    • Шахматные задачи
    • Правила игры в шахматы
    • Шахматные дебюты +
      • Открытые дебюты
      • Полуоткрытые дебюты +
        • Сицилианская защита
        • Французская защита
        • Защита Каро-Канн
        • Защита Пирца-Уфимцева
        • Скандинавская защита
        • Защита Алёхина
        • Дебют Нимцовича
        • Славянская защита
        • Отказанный ферзевый гамбит
        • Принятый ферзевый гамбит
        • Редкие варианты дебюта ферзевых пешек
        • Мат в 2 хода
        • Мат в 3 хода

        Шахматные задачи онлайн

        Мат в 5 ходов, автор Jean Lochet

        Кто не спит может чуть "размяться" и решить эту пятиходовку. Автор ее французский составитель задач Jean Lochet. Белые начинают и матуют в 5 ходов.

        Мат в 2 хода, автор задачи Imans Kulis

        Мат в 2 хода, автор задачи Imans Kulis

        Оказывается, задачи на сайте решают еще и люди с Дзена. Тогда постараемся публиковать их почаще. Автор этой шахматной композиции латвийский составитель задач Imans Kulis. Белые начинают и матуют в 2 хода (#2 vv. ).

        Ничейный этюд, автор Milu Milescu

        Ничейный этюд, автор Milu Milescu

        Автор этого этюда Milu Milescu - румыно-израильский составитель задач. Эта задача была составлена в 1961 году. Ничья.

        Мат в 4 хода, автор Franz Sackmann

        Мат в 4 хода, автор Franz Sackmann

        Автор этой задачи немецкий составитель задач Franz Sackmann. Опубликована композиция была в 1914 году. Белые начинают и матуют в 4 хода.

        Мат в 4 хода, автор Hyacinth R. Agnel

        Мат в 4 хода, автор Hyacinth R. Agnel

        Автор этой задачи американский составитель шахматных задач Hyacinth R. Agnel. Белые начинают и ставят мат в 4 хода. Задача опубликована в 1868 году.

        • мат в 1 ход
        • мат в 2 хода
        • мат в 3 хода
        • мат в 4 хода
        • мат в 5 ходов
        • выигрыш

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

        Шахматные задачи не только стимулируют интерес к игре, но и развивают логическое мышление, что немаловажно для развития ребенка.

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

        При подготовке материала использовались источники:
        https://habr.com/ru/companies/raiffeisenbank/articles/552136/
        http://guruchess.ru/%D1%88%D0%B0%D1%85%D0%BC%D0%B0%D1%82%D0%BD%D1%8B%D0%B5-%D0%B7%D0%B0%D0%B4%D0%B0%D1%87%D0%B8
        https://chessok.net/zadachi/