def main(): run = True clock = pygame.time.Clock() board = Board() active_click = 0 while run: clock.tick(FPS) for event in pygame.event.get(): #For exiting the game if event.type == pygame.QUIT: run = False #For clicking on screen if event.type == pygame.MOUSEBUTTONDOWN: if active_click == 1: pos = pygame.mouse.get_pos() row, col = return_row_col_of_mouse(pos) board.move_piece(piece, row, col) active_click = 0 else: pos = pygame.mouse.get_pos() row, col = return_row_col_of_mouse(pos) piece = board.return_piece(row, col) if piece != 0: active_click = 1 board.draw(WIN) pygame.display.update() pygame.quit()
class Game: def __init__(self, win): self.win = win self.color_value = {(255, 255, 255): "White", (0, 0, 0): "Black"} self._init() def _init(self): self.selected = None self.board = Board() self.turn = WHITE self.valid_moves = [] self.check_mate = False self.move_x, self.move_y = 805, 40 self.__draw_static_text() def __draw_static_text(self): self.win.fill(BLACK) display_text(self.win, SMALL_FONT, 'WHITE | BLACK | WHITE | BLACK', 800, 20, (255, 255, 255)) def update(self): self.board.draw(self.win) if self.selected: self.draw_valid_moves(self.valid_moves) if self.check_mate: display_text( self.win, LARGE_FONT, f"Check Mate!! {self.color_value.get(self.turn)} Wins!!", 250, 350, (255, 0, 0)) display_text(self.win, LARGE_FONT, "Press R to restart", 300, 450, (255, 0, 0)) pygame.display.update() def __display_moves(self, move): if self.turn == WHITE: display_text(self.win, SMALL_FONT, move, self.move_x, self.move_y, (255, 255, 255)) else: display_text(self.win, SMALL_FONT, move, self.move_x + 50, self.move_y, (255, 255, 255)) self.move_y += 20 if self.move_y > 780: self.move_x = 905 def reset(self): self._init() def __get_opposing_color(self, color): return BLACK if color == WHITE else WHITE def select(self, coordinate): """ Takes in a coordinate, if a piece is selected it will make the move on a temporary board to ensure it is valid. Otherwise a piece will be selected and its valid moves will be calculated :param coordinate: integer representing the selected board coordinate :return: boolean representing whether or not a piece has been selected """ if self.selected: destination_coordinate = coordinate temp_board = self.simulate_move(self.selected, destination_coordinate, self.board.get_board().copy()) if self.is_in_check(temp_board, self.__get_opposing_color(self.turn)): self.selected = None self.select(coordinate) result = self.__move(coordinate) if not result: self.selected = None self.select(coordinate) else: self.update() else: piece = self.board.get_piece(coordinate) if piece != 0 and piece.color == self.turn: self.selected = piece self.valid_moves = piece.calculate_legal_moves( self.board.get_board()) return True return False def get_king_position(self, current_board, color): for i in range(len(current_board)): if str(current_board[i] ) == 'King' and current_board[i].color == color: return i return -1 # Should not happen def is_in_check(self, current_board, color): temp_king_pos = self.get_king_position( current_board, self.__get_opposing_color(color)) enemy_pieces = self.board.get_player_pieces(color, current_board) current_enemy_moves = self.board.get_player_moves( enemy_pieces, current_board) return temp_king_pos in current_enemy_moves def is_check_mate(self, current_board, color): player_pieces = self.board.get_player_pieces(color, current_board) for piece in player_pieces: current_player_moves = piece.calculate_legal_moves(current_board) for move in current_player_moves: updated_board = self.simulate_move(piece, move, current_board.copy()) # if one of the moves does not result in check i.e. there is a valid move, return false if not self.is_in_check(updated_board, self.__get_opposing_color(color)): return False return True def simulate_move(self, piece, destination_coordinate, simulated_board): piece_position = piece.tile_index simulated_board[destination_coordinate] = piece simulated_board[piece_position] = 0 return simulated_board def __move(self, coordinate): if self.selected and coordinate in self.valid_moves: self.board.move(self.selected, coordinate) self.__display_moves(self.selected.notation + ALGEBRAIC_NOTATION[coordinate]) self.change_turn() else: return False return True def draw_valid_moves(self, moves): for move in moves: row = move // ROWS col = move % ROWS self.win.blit(GREEN_BOX, (col * SQUARE_SIZE, row * SQUARE_SIZE)) def change_turn(self): self.selected = None self.turn = WHITE if self.turn == BLACK else BLACK if self.is_check_mate(self.board.get_board(), self.turn): self.check_mate = True def get_current_player(self): return self.turn def get_board(self): return self.board def ai_move(self, board): current_board = self.board.get_board() piece = None coordinate = None # Find the Piece that was moved and its coordinate for i in range(len(board)): if current_board[i] != board[i] and board[i] != 0: piece = board[i] coordinate = i break if piece: self.__display_moves(piece.notation + ALGEBRAIC_NOTATION[coordinate]) self.board.move(piece, coordinate) else: print("COULDN'T FIND PIECE") self.change_turn() def evaluate(self, depth, current_board): """ Evaluates a given board using the helper functions below :param depth: integer representing how deep the minimax algorithm went :param current_board: :return: inteer representing the evaluated score """ return self.__check(current_board) + self.__checkmate( depth, current_board) + self.__mobility() + self.__piece_value( current_board) def __checkmate(self, depth, current_board): return CHECK_MATE_BONUS * self.__depth_bonus( depth) if self.is_check_mate( current_board, self.__get_opposing_color(self.turn)) else 0 def __depth_bonus(self, depth): return 1 if depth == 0 else DEPTH_BONUS * depth def __check(self, current_board): return CHECK_BONUS if self.is_in_check( current_board, self.__get_opposing_color(self.turn)) else 0 def __mobility(self): return len(self.valid_moves) def __piece_value(self, current_board): piece_value_score = 0 pieces = self.board.get_player_pieces(self.turn, current_board) for piece in pieces: piece_value_score += piece.piece_value return piece_value_score
class Game: def __init__(self, win, skill_level): self.win = win self.board = Board() self._initialize() self.engine = Engine(skill_level) self.buttons = [ Button(SQUARE_SIZE * 9, SQUARE_SIZE, SQUARE_SIZE, SQUARE_SIZE // 2, RED, "queen"), Button(SQUARE_SIZE * 9, SQUARE_SIZE * 2, SQUARE_SIZE, SQUARE_SIZE // 2, BLUE, "bishop"), Button(SQUARE_SIZE * 9, SQUARE_SIZE * 3, SQUARE_SIZE, SQUARE_SIZE // 2, GREEN, "knight"), Button(SQUARE_SIZE * 9, SQUARE_SIZE * 4, SQUARE_SIZE, SQUARE_SIZE // 2, ORANGE, "rook") ] def _initialize(self): self.selected = None self.turn = WHITE self.valid_moves = {} self.winner = None self.moves_since_pawn_move_or_capture = 0 self.past_positions = {self.board.get_position(): 1} self.move_count = 0 self.promotion_move = False def update(self): self.board.draw(self.win) self.draw_valid_moves() if self.promotion_move: for button in self.buttons: button.draw(self.win) def draw_valid_moves(self): for move in self.valid_moves: row, col = move pygame.draw.circle( self.win, LIGHT_BLUE, (col * SQUARE_SIZE + SQUARE_SIZE // 2 + BOARD_EDGE, row * SQUARE_SIZE + SQUARE_SIZE // 2 + BOARD_EDGE), POSSIBLE_MOVE_RADIUS) def make_engine_move(self): self.engine.set_position(self.get_current_fen()) move = self.engine.get_move(ENGINE_TIME_PER_MOVE) promotion = False if len(move) == 5: start_col, start_row, end_col, end_row, promotion = move start_col, end_col = ord(start_col) - ord('a'), ord(end_col) - ord( 'a') start_row, end_row = ROWS - int(start_row), ROWS - int(end_row) else: start_col, start_row, end_col, end_row = move start_col, end_col = ord(start_col) - ord('a'), ord(end_col) - ord( 'a') start_row, end_row = ROWS - int(start_row), ROWS - int(end_row) piece = self.board.get_piece(start_row, start_col) self.selected = piece self.valid_moves = piece.find_legal_moves(self.board.board) if promotion: self.board.move(self.selected, end_row, end_col, self.board.board) if promotion == "q": self.board.board[end_row][end_col] = piece.promote_to_queen() elif promotion == 'n': self.board.board[end_row][end_col] = piece.promote_to_knight() elif promotion == 'r': self.board.board[end_row][end_col] = piece.promote_to_rook() elif promotion == 'b': self.board.board[end_row][end_col] = piece.promote_to_bishop() self.board.remove(self.board.board, (start_row, start_col)) self.moves_since_pawn_move_or_capture = 0 current_position = self.board.get_position() self.update_past_positions() self.change_turn(current_position) else: self._move(end_row, end_col) time.sleep(1) def select(self, position): pos = self.get_position(position) if pos and not self.promotion_move: row, col = pos if self.selected: result = self._move(row, col) if not result: self.selected = None self.select(position) self.valid_moves = {} piece = self.board.get_piece(row, col) if piece is not None and piece.get_color() == self.turn: self.selected = piece self.valid_moves = self.board.find_legal_moves(piece) return True elif self.promotion_move: row, col = self.promotion_move piece = self.board.get_piece(row, col) for button in self.buttons: if button.clicked(position): piece_type = button.get_name() piece = self.board.get_piece(row, col) if piece_type == "queen": self.board.board[row][col] = piece.promote_to_queen() elif piece_type == "bishop": self.board.board[row][col] = piece.promote_to_bishop() elif piece_type == "knight": self.board.board[row][col] = piece.promote_to_knight() elif piece_type == "rook": self.board.board[row][col] = piece.promote_to_rook() self.promotion_move = False self.board.promotion_move = False self.update_past_positions() board_pos = self.board.get_position() self.change_turn(board_pos) self.moves_since_pawn_move_or_capture = 0 return True return False @staticmethod def get_position(position): x, y = position if BOARD_EDGE < x < WIDTH + BOARD_EDGE and BOARD_EDGE < y < HEIGHT + BOARD_EDGE: row = (y - BOARD_EDGE) // SQUARE_SIZE col = (x - BOARD_EDGE) // SQUARE_SIZE return row, col else: return None def _move(self, row, col): if self.selected and (row, col) in self.valid_moves: self.board.move(self.selected, row, col, self.board.board) capture = self.valid_moves[(row, col)] if capture: self.moves_since_pawn_move_or_capture = 0 capture_row, capture_col = capture if capture_row != row: # en passant self.board.remove(self.board.board, capture) elif isinstance(self.selected, Pawn): self.moves_since_pawn_move_or_capture = 0 else: self.moves_since_pawn_move_or_capture += 1 position = self.board.get_position() self.promotion_move = self.board.promotion_move if not self.promotion_move: self.update_past_positions() self.change_turn(position) else: return False return True def change_turn(self, position): self.valid_moves = {} self.board.stop_en_passant(self.turn) self.selected = None if self.turn == WHITE: self.turn = BLACK self.move_count += 1 else: self.turn = WHITE self.board.find_all_possible_moves(self.turn) if self.moves_since_pawn_move_or_capture == 100: self.winner = "Draw - 50 move rule" elif self.past_positions[position] == 3: self.winner = "Draw - 3 fold repetition" else: self.winner = self.board.checkmate_or_stalemate(self.turn) def reset(self): self.board.reset() self._initialize() def get_winner(self): return self.winner def check_promotion(self): piece = self.board.promotion_move if piece: self.board.promotion_move = False return piece return False def update_past_positions(self): position = self.board.get_position() if position in self.past_positions: self.past_positions[position] += 1 else: self.past_positions[position] = 1 def get_current_fen(self): return self.board.get_fen(self.turn, self.moves_since_pawn_move_or_capture, self.move_count)