Вот мой класс 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]
Мобильная версия