(self, move)
return san
Gets the standard algebraic notation of the given move in the context of
        the current position.

        There is no validation. It is only guaranteed to work if the move is
        legal or a null move.
Gets the standard algebraic notation of the given move in the context of
        the current position.
Gets the standard algebraic notation of the given move in the context of the current position .
def san(self, move):
        """
        Gets the standard algebraic notation of the given move in the context of
        the current position.

        There is no validation. It is only guaranteed to work if the move is
        legal or a null move.
        """

        if not move:
            # Null move.
            return "--"

        piece = self.piece_type_at(move.from_square)
        en_passant = False

        # Castling.
        if piece == KING:
            if move.from_square == E1:
                if move.to_square == G1:
                    return "O-O"
                elif move.to_square == C1:
                    return "O-O-O"
            elif move.from_square == E8:
                if move.to_square == G8:
                    return "O-O"
                elif move.to_square == C8:
                    return "O-O-O"

        if piece == PAWN:
            san = ""

            # Detect en-passant.
            if not BB_SQUARES[move.to_square] & self.occupied:
                en_passant = abs(move.from_square - move.to_square) in (7, 9)
        else:
            # Get ambigous move candidates.
            if piece == KNIGHT:
                san = "N"
                others = self.knights & self.knight_attacks_from(move.to_square)
            elif piece == BISHOP:
                san = "B"
                others = self.bishops & self.bishop_attacks_from(move.to_square)
            elif piece == ROOK:
                san = "R"
                others = self.rooks & self.rook_attacks_from(move.to_square)
            elif piece == QUEEN:
                san = "Q"
                others = self.queens & self.queen_attacks_from(move.to_square)
            elif piece == KING:
                san = "K"
                others = self.kings & self.king_attacks_from(move.to_square)

            others &= ~BB_SQUARES[move.from_square]
            others &= self.occupied_co[self.turn]

            # Remove illegal candidates.
            squares = others
            while squares:
                square, squares = next_bit(squares)

                if self.is_into_check(Move(square, move.to_square)):
                    others &= ~BB_SQUARES[square]

            # Disambiguate.
            if others:
                row, column = False, False

                if others & BB_RANKS[rank_index(move.from_square)]:
                    column = True

                if others & BB_FILES[file_index(move.from_square)]:
                    row = True
                else:
                    column = True

                if column:
                    san += FILE_NAMES[file_index(move.from_square)]
                if row:
                    san += str(rank_index(move.from_square) + 1)

        # Captures.
        if BB_SQUARES[move.to_square] & self.occupied or en_passant:
            if piece == PAWN:
                san += FILE_NAMES[file_index(move.from_square)]
            san += "x"

        # Destination square.
        san += SQUARE_NAMES[move.to_square]

        # Look ahead for check or checkmate.
        self.push(move)
        if self.is_check():
            if self.is_checkmate():
                san += "#"
            else:
                san += "+"
        self.pop()

        return san
def san ( self , move ) : if not move : # Null move. return "--" piece = self . piece_type_at ( move . from_square ) en_passant = False # Castling. if piece == KING : if move . from_square == E1 : if move . to_square == G1 : return "O-O" elif move . to_square == C1 : return "O-O-O" elif move . from_square == E8 : if move . to_square == G8 : return "O-O" elif move . to_square == C8 : return "O-O-O" if piece == PAWN : san = "" # Detect en-passant. if not BB_SQUARES [ move . to_square ] & self . occupied : en_passant = abs ( move . from_square - move . to_square ) in ( 7 , 9 ) else : # Get ambigous move candidates. if piece == KNIGHT : san = "N" others = self . knights & self . knight_attacks_from ( move . to_square ) elif piece == BISHOP : san = "B" others = self . bishops & self . bishop_attacks_from ( move . to_square ) elif piece == ROOK : san = "R" others = self . rooks & self . rook_attacks_from ( move . to_square ) elif piece == QUEEN : san = "Q" others = self . queens & self . queen_attacks_from ( move . to_square ) elif piece == KING : san = "K" others = self . kings & self . king_attacks_from ( move . to_square ) others &= ~ BB_SQUARES [ move . from_square ] others &= self . occupied_co [ self . turn ] # Remove illegal candidates. squares = others while squares : square , squares = next_bit ( squares ) if self . is_into_check ( Move ( square , move . to_square ) ) : others &= ~ BB_SQUARES [ square ] # Disambiguate. if others : row , column = False , False if others & BB_RANKS [ rank_index ( move . from_square ) ] : column = True if others & BB_FILES [ file_index ( move . from_square ) ] : row = True else : column = True if column : san += FILE_NAMES [ file_index ( move . from_square ) ] if row : san += str ( rank_index ( move . from_square ) + 1 ) # Captures. if BB_SQUARES [ move . to_square ] & self . occupied or en_passant : if piece == PAWN : san += FILE_NAMES [ file_index ( move . from_square ) ] san += "x" # Destination square. san += SQUARE_NAMES [ move . to_square ] # Look ahead for check or checkmate. self . push ( move ) if self . is_check ( ) : if self . is_checkmate ( ) : san += "#" else : san += "+" self . pop ( ) return san