Ejemplo n.º 1
0
    def make_safe_move(self, move: Union[Move, str]):
        """
        Same as Board.make_move, but validates if the move is legal first (slower).
        """
        if isinstance(move, str):
            move = Move.from_uci(move)

        if move in self.legal_moves:
            self.make_move(move)
        else:
            raise IllegalMove(f"Move {move} is illegal.")
Ejemplo n.º 2
0
    def make_move(self, move: Union[Move, str]):
        """
        Moves a piece on the game. Warning: moves are not checked for legality in this function, this is for speed.
        The consumer of this API should enforce legality by checking Bitboard.legal_moves.
        """

        if isinstance(move, str):
            move = Move.from_uci(move)

        self._save()
        piece = self.piece_at(move.from_square)
        captured_piece = self.piece_at(move.to_square)

        if not piece:
            raise IllegalMove(f"No piece at {move.from_square}")

        if piece.colour != self.turn:
            raise IllegalMove(f"Can't move that piece, it's not your turn.")

        backrank = 7 if self.turn == WHITE else 0

        # Castling if a king is moving more than 1 square
        if piece.type == KING and abs(move.from_square.file -
                                      move.to_square.file) > 1:
            # Move King
            self.remove_piece(move.from_square)
            self.place_piece(move.to_square, piece.type, piece.colour)

            # Move Rook
            rook_shift = 1 if move.to_square.file < move.from_square.file else -1  # For Queen/Kingside
            if rook_shift > 0:  # Queenside
                self.remove_piece(Square.from_file_rank(
                    0, move.to_square.rank))
            else:
                self.remove_piece(Square.from_file_rank(
                    7, move.to_square.rank))

            self.place_piece(
                Square.from_file_rank(move.to_square.file + rook_shift,
                                      move.from_square.rank),
                ROOK,
                piece.colour,
            )

            self.repetitions = []  # Reset repetitions when castling
        elif piece.type == PAWN and move.to_square == self.en_passant_sq:  # Take piece by en_passant
            shift = -8 if piece.colour == WHITE else 8
            capture_sq = self.en_passant_sq + shift
            captured_piece = self.remove_piece(capture_sq)
            self.remove_piece(move.from_square)
            self.place_piece(move.to_square, piece.type, piece.colour)
        elif piece.type == PAWN and move.to_square.rank == backrank:  # Promotion
            self.remove_piece(move.from_square)
            self.place_piece(move.to_square, move.promotion,
                             piece.colour)  # Assume queen for now
        else:
            # Regular piece move
            self.remove_piece(move.from_square)
            self.place_piece(move.to_square, piece.type, piece.colour)

        # Set En Passant square
        if piece.type == PAWN:
            distance = move.to_square.rank - move.from_square.rank
            if abs(distance) == 2:
                if distance > 0:  # White pawn goes from low rank to higher
                    self.en_passant_sq = Square(
                        move.from_square +
                        8)  # En Passant square is 1 rank behind
                else:  # Black pawn
                    self.en_passant_sq = Square(move.from_square - 8)
            else:
                self.en_passant_sq = None
        else:
            self.en_passant_sq = None

        # Update castling rights if the king or rook move
        if piece.type in (KING, ROOK):
            self._update_castling_rights()

        # Reset halfmove clock if a pawn moved or a piece was captured
        if piece.type == PAWN or captured_piece:
            self.halfmove_clock = 0
            self.repetitions = []
        else:
            self.halfmove_clock += 1
            if self.track_repetitions:
                self.repetitions.append(
                    self._short_fen)  # Imperfect repetition tracking

        if self.turn == BLACK:  # Increment full moves after Black's turn
            self.fullmoves += 1

        self.move_history.append(move)
        self.turn = not self.turn