Сегодня каждый процесс пытаются автоматизировать. Сейчас умение делать ботов должно быть практически у любого программиста. В этой статье я поделюсь с вами, как cделать бота в шахматах на Python.
Для начала пропишем все нужные нам библиотеки:
import chess as ch #импортируем библиотеку питона
import random as rd
Модуль chess представляет собой чистую шахматную библиотеку Python с генерацией ходов, проверкой ходов и поддержкой распространенных форматов. Мы можем играть с ним в шахматы. Это поможет нам ходить королем, ферзем, пешкой, слонами и конями. Нам нужно знать основы шахмат, чтобы играть с ними. Этот модуль выполняет все задачи на питоне, которые возможны в реальной игре.
Далее мы вводим доску, цвет фигур и правила игры:
class Engine:
def __init__(self, board, maxDepth, color):
self.board = board
self.color = color
self.maxDepth = maxDepth
def getBestMove(self):
return self.engine(None, 1)
def evalFunct(self):
compt = 0
# симмируем все вещественные числа
for i in range(64):
compt += self.squareResPoints(ch.SQUARES[i])
compt += self.mateOpportunity() + self.openning() + 0.001 * rd.random()
return compt
def mateOpportunity(self):
if (self.board.legal_moves.count() == 0):
if (self.board.turn == self.color):
return -999
else:
return 999
else:
return 0
Классы служат для категоризации объектов и используются для превращения абстрактной идеи в этой категории в реальный объект. Используя пример со стулом, существует целый ряд различных видов стульев от кресел-мешков с фасолью до стандартных деревянных стульев. Объект создается, когда в класс передается достаточно данных, чтобы помочь вам создать коричневый стул, который не катится на 4 ножках в точке (0,0). Как и в реальной жизни, вы можете создать несколько стульев с одними и теми же данными, и они все равно останутся разными объектами. Вот пример:
Прописываем первый ход для движка:
# первый ход
def openning(self):
if (self.board.fullmove_number < 10):
if (self.board.turn == self.color):
return 1 / 30 * self.board.legal_moves.count()
else:
return -1 / 30 * self.board.legal_moves.count()
else:
return 0
Далее пропишем ценность каждой фигуры:
# прописываем ценность каждой из фигур
def squareResPoints(self, square):
pieceValue = 0
if (self.board.piece_type_at(square) == ch.PAWN):
pieceValue = 1
elif (self.board.piece_type_at(square) == ch.ROOK):
pieceValue = 5.1
elif (self.board.piece_type_at(square) == ch.BISHOP):
pieceValue = 3.33
elif (self.board.piece_type_at(square) == ch.KNIGHT):
pieceValue = 3.2
elif (self.board.piece_type_at(square) == ch.QUEEN):
pieceValue = 8.8
if (self.board.color_at(square) != self.color):
return -pieceValue
else:
return pieceValue
Фигура описывается своим именем и цветом и имеет метод, который проверяет, является ли перемещение фигуры из точки А в точку Б допустимым ходом в соответствии с правилами конкретной фигуры.
Дальше правила игры для бота:
def engine(self, candidate, depth):
# достигнута максимальная глубина поиска или нет возможных ходов
if (depth == self.maxDepth
or self.board.legal_moves.count() == 0):
return self.evalFunct()
else:
# получить список допустимых ходов текущей позиции
moveListe = list(self.board.legal_moves)
# инициализация нового игрока
newCandidate = None
# (uneven depth means engine's turn)
if (depth % 2 != 0):
newCandidate = float("-inf")
else:
newCandidate = float("inf")
# анализируем доску после более глубоких ходов
for i in moveListe:
# мои игровые хожы
self.board.push(i)
# Получить ценность моих ходов(исследуя последствия)
value = self.engine(newCandidate, depth + 1)
# Базовый алгоритм минмакс:
# при максимизации
if (value > newCandidate and depth % 2 != 0):
# нужно сохранить ход, сыгранный движком
if (depth == 1):
move = i
newCandidate = value
# при минимизации
elif (value < newCandidate and depth % 2 == 0):
newCandidate = value
# (если предыдущий ход был сделан Engine)
if (candidate != None
and value < candidate
and depth % 2 == 0):
self.board.pop()
break
# (if previous move was made by the human player)
elif (candidate != None
and value > candidate
and depth % 2 != 0):
self.board.pop()
break
# Отменяем последний ход
self.board.pop()
# возвращаем результат
if (depth > 1):
# возвращаемое значение хода в дереве
return newCandidate
else:
# возвращаем ход (только на первый ход)
return move
Итак, с ботом закончили. Приступим к написанию самой игры.
Вводим нужные библиотеки и класс Main:
import ChessEngine as ce
import chess as ch
class Main:
def __init__(self, board=ch.Board):
self.board = board
Далее прописываем ходы человека и бота:
# ходы человека
def playHumanMove(self):
try:
print(self.board.legal_moves)
print("""To undo your last move, type "undo".""")
# Наши возможные ходы
play = input("Your move: ")
if (play == "undo"):
self.board.pop()
self.board.pop()
self.playHumanMove()
return
self.board.push_san(play)
except:
self.playHumanMove()
# ходы бота
def playEngineMove(self, maxDepth, color):
engine = ce.Engine(self.board, maxDepth, color)
self.board.push(engine.getBestMove())
А также как начать новую игру, выбор цвета и т.д.
# начало игры
def startGame(self):
# выбор цвета
color = None
while (color != "b" and color != "w"):
color = input("""Play as (type "b" or "w"): """)
maxDepth = None
while (isinstance(maxDepth, int) == False):
maxDepth = int(input("""Choose depth: """))
if color == "b":
while (self.board.is_checkmate() == False):
print("The engine is thinking...")
self.playEngineMove(maxDepth, ch.WHITE)
print(self.board)
self.playHumanMove()
print(self.board)
print(self.board)
print(self.board.outcome())
elif color == "w":
while (self.board.is_checkmate() == False):
print(self.board)
self.playHumanMove()
print(self.board)
print("The engine is thinking...")
self.playEngineMove(maxDepth, ch.BLACK)
print(self.board)
print(self.board.outcome())
# сбросить данную игру
self.board.reset
# начать другую игру
self.startGame()
Небольшая справка
По новым правилам от июля 2014 года игра заканчивается ничьей (даже без претензии) после пятикратного повторения или если есть 75 ходов без проталкивания или взятия пешки. Другие способы окончания игры имеют приоритет.
Ну и последнее. Создать доску и начать игру
newBoard = ch.Board()
game = Main(newBoard)
bruh = game.startGame()
Весь код проекта: https://github.com/KITIN55/Chess
Надеюсь вам понравилась данная статья и вы нашли ее полезной. Жду ваши идеи в комментариях.