Мне нужна помощь в создании шахматного ИИ с использованием минимаксного алгоритма.Python

Программы на Python
Ответить Пред. темаСлед. тема
Anonymous
 Мне нужна помощь в создании шахматного ИИ с использованием минимаксного алгоритма.

Сообщение Anonymous »

Мне нужна помощь в создании шахматного ИИ с использованием минимаксного алгоритма и альфа-бета-обрезки для моего проекта на Python. Также я хочу переключаться между ИИ и игроком, перемещающим черные фигуры, нажимая «a», я пытался это сделать, но это не работает должным образом.
Вот мой класс Piece:< /p>

Код: Выделить всё

import os

class Piece:

def __init__(self, name, color, value, texture=None, texture_rect=None):
self.name = name
self.color = color
value_sign = 1 if color == 'white' else -1
self.value = value * value_sign
self.moves = []
self.moved = False
self.texture = texture
self.set_texture()
self.texture_rect = texture_rect

def set_texture(self, size=80):
self.texture = os.path.join(
f'assets/images/imgs-{size}px/{self.color}_{self.name}.png')

def add_moves(self, move):
self.moves.append(move)

def clear_moves(self):
self.moves = []

class Pawn(Piece):

def __init__(self, color):
super().__init__('pawn', color, 1.0)

if color == 'white':
self.direction = -1
else:
self.direction = 1

self.en_passant = False

class Knight(Piece):

def __init__(self, color):
super().__init__('knight', color, 3.0)

class Bishop(Piece):

def __init__(self, color):
super().__init__('bishop', color, 3.001)

class Rook(Piece):

def __init__(self, color):
super().__init__('rook', color, 5.0)

class Queen(Piece):

def __init__(self, color):
super().__init__('queen', color, 9.0)

class King(Piece):

def __init__(self, color):
self.left_rook = None
self.right_rook = None
super().__init__('king', color, 10000.0)
Мой класс доски:

Код: Выделить всё

import copy
import os

from const import *
from square import Square
from piece import *
from move import Move
from sound import Sound

class Board:

def __init__(self):
self.squares = [[0, 0, 0, 0, 0, 0, 0, 0] for col in range(COLUMNS)]
self.last_move = None

self.create_board()
self.add_pieces('white')
self.add_pieces('black')

def create_board(self):
for row in range(ROWS):
for col in range(COLUMNS):
self.squares[row][col] = Square(row, col)

def add_pieces(self, color):
if color == 'white':
row_pawn, row_other = (6, 7)
else:
row_pawn, row_other = (1, 0)

# Pawns
for col in range(COLUMNS):
self.squares[row_pawn][col] = Square(row_pawn, col, Pawn(color))

# Knights
self.squares[row_other][1] = Square(row_other, 1, Knight(color))
self.squares[row_other][6] = Square(row_other, 6, Knight(color))

# Bishops
self.squares[row_other][2] = Square(row_other, 2, Bishop(color))
self.squares[row_other][5] = Square(row_other, 5, Bishop(color))

# Rooks
self.squares[row_other][0] = Square(row_other, 0, Rook(color))
self.squares[row_other][7] = Square(row_other, 7, Rook(color))

# Queen
self.squares[row_other][3] = Square(row_other, 3, Queen(color))

# King
self.squares[row_other][4] = Square(row_other, 4, King(color))

def calc_moves(self, piece, row, col, bool=True):

def pawn_moves():
if piece.moved:
steps = 1
else:
steps = 2

# Vertical moves
start = row + piece.direction
end = row + (piece.direction * (1 + steps))

for possible_move_row in range(start, end, piece.direction):
if Square.in_range(possible_move_row):
if self.squares[possible_move_row][col].is_empty():
initial = Square(row, col)
final = Square(possible_move_row, col)

move = Move(initial, final)

if bool:
if not self.in_check(piece,  move):
piece.add_moves(move)
else:
piece.add_moves(move)

else:
break
else:
break

# Diagonal moves
possible_move_row = row + piece.direction
possible_move_cols = [col - 1, col + 1]

for possible_move_col in possible_move_cols:
if Square.in_range(possible_move_row, possible_move_col):
if self.squares[possible_move_row][possible_move_col].has_opponent_piece(piece.color):
initial = Square(row, col)
final_piece = self.squares[possible_move_row][possible_move_col].piece
final = Square(possible_move_row, possible_move_col, final_piece)

move = Move(initial, final)

if bool:
if not self.in_check(piece, move):
piece.add_moves(move)
else:
piece.add_moves(move)

# En passant moves
if piece.color == 'white':
r = 3
else:
r = 4

if piece.color == 'white':
final_r = 2
else:
final_r = 5

# Left en passant
if Square.in_range(col-1) and row == r:
if self.squares[row][col-1].has_opponent_piece(piece.color):
p = self.squares[row][col-1].piece
if isinstance(p, Pawn):
if p.en_passant:
initial = Square(row, col)
final_piece = self.squares[row][col-1].piece
final = Square(final_r, col-1, p)

move = Move(initial, final)

if bool:
if not self.in_check(piece, move):
piece.add_moves(move)
else:
piece.add_moves(move)

# Right an passant
if Square.in_range(col+1) and row == r:
if self.squares[row][col+1].has_opponent_piece(piece.color):
p = self.squares[row][col+1].piece
if isinstance(p, Pawn):
if p.en_passant:
initial = Square(row, col)
final_piece = self.squares[row][col+1].piece
final = Square(final_r, col+1, p)

move = Move(initial, final)

if bool:
if not self.in_check(piece, move):
piece.add_moves(move)
else:
piece.add_moves(move)

def knight_moves():
possible_moves = [
(row-2, col+1),
(row-1, col+2),
(row+1, col+2),
(row+2, col+1),
(row+2, col-1),
(row+1, col-2),
(row-1, col-2),
(row-2, col-1)
]

for possible_move in possible_moves:
possible_move_row, possible_move_col = possible_move
if Square.in_range(possible_move_row, possible_move_col):
if self.squares[possible_move_row][possible_move_col].is_empty_or_opponent_piece(piece.color):

# Create squares
initial = Square(row, col)
final_piece = self.squares[possible_move_row][possible_move_col].piece
final = Square(possible_move_row, possible_move_col, final_piece)

# Create and append new move
move = Move(initial, final)

if bool:
if not self.in_check(piece, move):
piece.add_moves(move)
else:
break
else:
piece.add_moves(move)

def straight_line_moves(incrs):
for incr in incrs:
row_incr,  col_incr = incr
possible_move_row = row + row_incr
possible_move_col = col + col_incr

while True:
if Square.in_range(possible_move_row, possible_move_col):

initial = Square(row, col)
final_piece = self.squares[possible_move_row][possible_move_col].piece
final = Square(possible_move_row, possible_move_col, final_piece)

move = Move(initial, final)

if self.squares[possible_move_row][possible_move_col].is_empty():
if bool:
if not self.in_check(piece, move):
piece.add_moves(move)
else:
piece.add_moves(move)

elif self.squares[possible_move_row][possible_move_col].has_opponent_piece(piece.color):
if bool:
if not self.in_check(piece, move):
piece.add_moves(move)
else:
piece.add_moves(move)
break

elif self.squares[possible_move_row][possible_move_col].has_player_piece(piece.color):
break

else:
break

possible_move_row = possible_move_row + row_incr
possible_move_col = possible_move_col + col_incr

def king_moves():
adjs = [
(row-1, col+0),  # up
(row-1, col+1),  # up-right
(row+0, col+1),  # right
(row+1, col+1),  # down-right
(row+1, col+0),  # down
(row+1, col-1),  # down-left
(row+0, col-1),  # left
(row-1, col-1)  # up-left
]

# Normal moves
for possible_move in adjs:
possible_move_row, possible_move_col = possible_move

if Square.in_range(possible_move_row, possible_move_col):
if self.squares[possible_move_row][possible_move_col].is_empty_or_opponent_piece(piece.color):
initial = Square(row, col)
final = Square(possible_move_row, possible_move_col)

move = Move(initial, final)

if bool:
if not self.in_check(piece, move):
piece.add_moves(move)
else:
break
else:
piece.add_moves(move)

# Castle move
if not piece.moved:

# Queen side castling
left_rook = self.squares[row][0].piece
if isinstance(left_rook, Rook):
if not left_rook.moved:
for c in range(1, 4):
if self.squares[row][c].has_piece():
break

if c == 3:
piece.left_rook = left_rook

# Rook move
initial = Square(row, 0)
final = Square(row, 3)
move_rook = Move(initial, final)

# King move
initial = Square(row, col)
final = Square(row, 2)
move_king = Move(initial, final)

if bool:
if not self.in_check(piece, move_king) and not self.in_check(left_rook, move_rook):
left_rook.add_moves(move_rook)
piece.add_moves(move_king)
else:
left_rook.add_moves(move_rook)
piece.add_moves(move_king)

# King side castling
right_rook = self.squares[row][7].piece
if isinstance(right_rook, Rook):
if not right_rook.moved:
for c in range(5,  7):
if self.squares[row][c].has_piece():
break

if c == 6:
piece.right_rook = right_rook

# Rook move
initial = Square(row, 7)
final = Square(row, 5)
move_rook = Move(initial, final)
right_rook.add_moves(move)

# King move
initial = Square(row, col)
final = Square(row, 6)
move_king = Move(initial, final)

if bool:
if not self.in_check(piece, move_king) and not self.in_check(right_rook, move_rook):
right_rook.add_moves(move_rook)
piece.add_moves(move_king)
else:
right_rook.add_moves(move_rook)
piece.add_moves(move_king)

if isinstance(piece, Pawn):
pawn_moves()

elif isinstance(piece, Knight):
knight_moves()

elif isinstance(piece, Bishop):
straight_line_moves([
(-1, 1),  # up-right diagonal
(-1, -1),  # up-left diagonal
(1, 1),  # down-right diagonal
(1, -1)  # down-left diagonal
])

elif isinstance(piece, Rook):
straight_line_moves([
(-1, 0),  # up
(0, 1),  # right
(1, 0),  # down
(0, -1)  # left
])

elif isinstance(piece, Queen):
straight_line_moves([
(-1, 1),
(-1, -1),
(1, 1),
(1, -1),
(-1, 0),
(0, 1),
(1, 0),
(0, -1)
])

elif isinstance(piece, King):
king_moves()

def move(self, piece, move, testing=False):
initial = move.initial
final = move.final

en_passant_empty = self.squares[final.row][final.col].is_empty()

self.squares[initial.row][initial.col].piece = None
self.squares[final.row][final.col].piece = piece

# Pawn en passant and promotion
if isinstance(piece, Pawn):

# En passant capture
diff = final.col - initial.col
if diff != 0 and en_passant_empty:
self.squares[initial.row][initial.col + diff].piece = None
self.squares[final.row][final.col].piece = piece

if not testing:
sound = Sound(os.path.join('assets/sounds/capture.wav'))
sound.play()

# Pawn promotion
else:
self.check_promotion(piece, final)

# King castle
if isinstance(piece, King):
if self.castling(initial, final) and not testing:
diff = final.col - initial.col

if diff <  0:
rook = piece.left_rook
else:
rook = piece.right_rook

self.move(rook, rook.moves[-1])

piece.moved = True

piece.clear_moves()

self.last_move = move

def valid_move(self, piece, move):
return move in piece.moves

def check_promotion(self, piece, final):
if final.row == 0 or final.row == 7:
self.squares[final.row][final.col].piece = Queen(piece.color)

def castling(self, initial, final):
return abs(initial.col - final.col) == 2

def set_true_en_passant(self, piece):
if not isinstance(piece, Pawn):
return

for row in range(ROWS):
for col in range(COLUMNS):
if isinstance(self.squares[row][col].piece, Pawn):
self.squares[row][col].piece.en_passant = False

piece.en_passant = True

def in_check(self, piece, move):
temp_piece = copy.deepcopy(piece)
temp_board = copy.deepcopy(self)
temp_board.move(temp_piece, move, testing=True)

for row in range(ROWS):
for col in range(COLUMNS):
if temp_board.squares[row][col].has_opponent_piece(piece.color):
p = temp_board.squares[row][col].piece
temp_board.calc_moves(p, row, col, bool=False)
for m in p.moves:
if isinstance(m.final.piece, King):
return True

return False

мой основной класс:

Код: Выделить всё

import pygame
import sys

from const import *
from game import Game
from square import Square
from move import Move
from ai import AI

class Main:

def __init__(self):
pygame.init()
self.screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Chess")
self.game = Game()
self.ai = AI('black')
self.player_turn = True

def mainloop(self):

screen = self.screen
game = self.game
board = self.game.board
dragger = self.game.dragger

while True:
game.show_bg(screen)
game.show_last_move(screen)
game.show_moves(screen)
game.show_pieces(screen)

game.show_hover(screen)

if dragger.dragging:
dragger.update_blit(screen)

for event in pygame.event.get():

# Mouse click
if event.type == pygame.MOUSEBUTTONDOWN:
dragger.update_mouse(event.pos)

clicked_row = dragger.mouseY // SQUARE_SIZE
clicked_col = dragger.mouseX // SQUARE_SIZE

if board.squares[clicked_row][clicked_col].has_piece():
piece = board.squares[clicked_row][clicked_col].piece
if piece.color == game.next_player:
board.calc_moves(piece, clicked_row, clicked_col, bool=True)
dragger.save_initial(event.pos)
dragger.drag_piece(piece)

game.show_bg(screen)
game.show_last_move(screen)
game.show_moves(screen)
game.show_pieces(screen)

# Mouse movement
elif event.type == pygame.MOUSEMOTION:
motion_row = event.pos[1] // SQUARE_SIZE
motion_col = event.pos[0] // SQUARE_SIZE

game.set_hover(motion_row,  motion_col)
if dragger.dragging:
dragger.update_mouse(event.pos)
game.show_bg(screen)
game.show_last_move(screen)
game.show_moves(screen)
game.show_pieces(screen)
game.show_hover(screen)
dragger.update_blit(screen)

# Mouse release
elif event.type == pygame.MOUSEBUTTONUP:
if dragger.dragging:
dragger.update_mouse(event.pos)

released_row = dragger.mouseY // SQUARE_SIZE
released_col = dragger.mouseX // SQUARE_SIZE

initial = Square(dragger.initial_row, dragger.initial_col)
final = Square(released_row, released_col)
move = Move(initial, final)

if board.valid_move(dragger.piece, move):
captured = board.squares[released_row][released_col].has_piece()
board.move(dragger.piece, move)

board.set_true_en_passant(dragger.piece)

game.play_sound(captured)
game.show_bg(screen)
game.show_last_move(screen)
game.show_pieces(screen)

game.next_turn()

dragger.undrag_piece()

elif event.type == pygame.KEYDOWN:

# Change theme
if event.key == pygame.K_t:
game.change_theme()

if event.key == pygame.K_a:
self.player_turn = not self.player_turn
if not self.player_turn:
move = self.ai.get_move(board)
piece = board.squares[move.initial.row][move.initial.col].piece
board.move(piece, move)
game.next_turn()

# Restart game
if event.key == pygame.K_r:
game.reset_game()

screen = self.screen
game = self.game
board = self.game.board
dragger = self.game.dragger

# Quit
elif event.type == pygame.QUIT:
pygame.quit()
sys.exit()

pygame.display.update()

main = Main()
main.mainloop()
и, наконец, мой урок по искусственному интеллекту:

Код: Выделить всё

import copy

from const import *

class AI:

def __init__(self, color):
self.color = color
self.opponent_color = 'white' if color == 'black' else 'black'
self.transposition_table = {}

def evaluate_board(self, board):
total_evaluation = 0
for row in range(ROWS):
for col in range(COLUMNS):
piece = board.squares[row][col].piece
if piece is not None:
total_evaluation += piece.value
return total_evaluation

def get_all_moves(self, board, color):
all_moves = []
for row in range(ROWS):
for col in range(COLUMNS):
piece = board.squares[row][col].piece
if piece is not None and piece.color == color:
board.calc_moves(piece, row, col)
all_moves.extend(piece.moves)
return all_moves

def minimax(self, board, depth, alpha, beta, maximizing):
board_state = str(board.squares)  # Unique representation of the board state
if board_state in self.transposition_table:
return self.transposition_table[board_state]

if depth == 0:
evaluation = self.evaluate_board(board)
self.transposition_table[board_state] = (evaluation, None)
return evaluation, None

best_move = None

if maximizing:
max_eval = float('-inf')
for move in self.get_all_moves(board, self.color):
temp_board = copy.deepcopy(board)
piece = temp_board.squares[move.initial.row][move.initial.col].piece
temp_board.move(piece,  move)
evaluation = self.minimax(temp_board, depth - 1, alpha, beta, False)[0]
if evaluation > max_eval:
max_eval = evaluation
best_move = move
alpha = max(alpha, evaluation)
if beta 

Подробнее здесь: [url]https://stackoverflow.com/questions/78699601/i-need-assisstation-with-creating-a-chess-ai-using-minimax-algorithm[/url]
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Python»