def place_piece(self, piece, square): """ Places piece on board at square specified Input piece can be str(K) or Piece Input square can be one of: - str('E4'), - tuple of array coordinates((0,2)) - Piece with file and rank properties """ if type(square) is str: file = FILE[square[0]] rank = RANK[square[1]] elif type(square) is Piece: file = square.file rank = square.rank else: rank = square[0] file = square[1] if type(piece) is str: piece = Piece(piece, rank=rank, file=file) else: piece.rank = rank piece.file = file self.BOARD[rank][file] = piece
def get_possible_squares(self, piece=None, square=None): """ Returns a list of possible squares availale to move to. Input needed: One of: piece or square, or both piece can be one of: string - 'K' Piece - Piece('K') square can be one of: string - 'E4' array coordinates - [3,5] Usage: get_possible_squares(piece='K', square='E4') get_possible_squares(square='E4') get_possible_squares(piece=<Piece>) // Piece with .file and .rank get_possible_squares(square=<Piece>) // Piece with .file and .rank """ #print(f"piece:{piece}, square:{square}") # if both piece and square are None if not piece and not square: return None # piece can be string or Piece object or empty if type(piece) is str: piece_obj = Piece(piece) elif type(piece) is Piece: piece_obj = piece else: piece_obj = self.board.BOARD[RANK[square[1]]][FILE[square[0]]] # square can be empty, string or array coordinates if not square: file = piece_obj.file rank = piece_obj.rank elif type(square) is str: file = FILE[square[0]] rank = RANK[square[1]] else: file = square[1] rank = square[0] # If no piece enterred and square is EMPTY: if not piece and self.board.BOARD[rank][file] is EMPTY: return None # If piece is newly created without file and rank if not piece_obj.file: piece_obj.file = file piece_obj.rank = rank # If not active colour if piece_obj.colour is not self.whose_move(): return None #print(f"get_possible_squares({piece_obj._id} on {Board.square_name((piece_obj.rank, piece_obj.file))})") # Loop through directions of piece movements possible_squares = [] for movement in piece_obj.movements: distance = 0 possible_file = file possible_rank = rank max_distance = piece_obj.max_distance # Loop until range of piece is exceeded while distance != max_distance: # If pawn on starting position if piece_obj.name is PAWN: if piece_obj.colour == WHITE and rank == 1 or \ piece_obj.colour == BLACK and rank == 6: max_distance = 2 # copy board for testing in_check conditions possible_board = Board(self.board.BOARD) possible_file += movement[1] possible_rank += movement[0] # If passed edge of board if possible_file < 0 or possible_file > 7 or \ possible_rank < 0 or possible_rank > 7: #print("Can't move: off edge of board") break possible_square = possible_board.BOARD[possible_rank][ possible_file] # If square is occupied if possible_square is not EMPTY: # If own piece in the way if possible_square.colour == piece_obj.colour: break # If opposition piece in the way else: # If moving piece is a pawn if piece_obj.name == PAWN: # If forward pawn move if movement in piece_obj.normal_movements: break # Test for putting self in check possible_board.remove_piece((rank, file)) possible_board.place_piece(square=possible_square, piece=piece_obj._id) if self.in_check(board=possible_board, colour=piece_obj.colour): break # Can capture piece else: possible_squares.append( [possible_rank, possible_file]) break # Square not occupied else: # If pawn if piece_obj.name == PAWN: # Can't move diagonal if not capturing unless en-passant if movement in piece_obj.capture_movements: if not self.en_passant_sq: break elif self.en_passant_sq and \ Board.square_name((possible_rank, possible_file)) != self.en_passant_sq.upper(): break # If not on 2nd rank(WHITE) or 7th rank(BLACK): Can't move two squares if piece_obj.colour == WHITE and rank != 1 and distance == 1 or \ piece_obj.colour == BLACK and rank != 6 and distance == 1: break # If Castling King if piece_obj.name is KING and piece_obj.colour is WHITE: if movement is E and self.castling_rights[0]: if max_distance == 1: max_distance = 2 if movement is W and self.castling_rights[1]: if max_distance == 1: max_distance = 2 elif piece_obj.name is KING and piece_obj.colour is BLACK: if movement is E and self.castling_rights[2]: if max_distance == 1: max_distance = 2 if movement is W and self.castling_rights[3]: if max_distance == 1: max_distance = 2 # Test for putting self in check possible_board.remove_piece((rank, file)) possible_board.place_piece(square=(possible_rank, possible_file), piece=piece_obj._id) if not self.in_check(board=possible_board, colour=piece_obj.colour): possible_squares.append([possible_rank, possible_file]) else: # Can't castle through a check if piece_obj.name is KING: max_distance = 1 distance += 1 if not possible_squares: return None else: return possible_squares