shogi/__init__.py
def set_sfen(self, sfen):
        '''
        Parses a SFEN and sets the position from it.
        Rasies `ValueError` if the SFEN string is invalid.
        '''
        # Ensure there are six parts.
        parts = sfen.split()
        if len(parts) != 4:
            raise ValueError('sfen string should consist of 6 parts: {0}'.format(repr(sfen)))

        # Ensure the board part is valid.
        rows = parts[0].split('/')
        if len(rows) != 9:
            raise ValueError('expected 9 rows in position part of sfen: {0}'.format(repr(sfen)))

        # Validate each row.
        for row in rows:
            field_sum = 0
            previous_was_digit = False
            previous_was_plus = False

            for c in row:
                if c in ['1', '2', '3', '4', '5', '6', '7', '8', '9']:
                    if previous_was_digit:
                        raise ValueError('two subsequent digits in position part of sfen: {0}'.format(repr(sfen)))
                    if previous_was_plus:
                        raise ValueError('Cannot promote squares in position part of sfen: {0}'.format(repr(sfen)))
                    field_sum += int(c)
                    previous_was_digit = True
                    previous_was_plus = False
                elif c == '+':
                    if previous_was_plus:
                        raise ValueError('Double promotion prefixes in position part of sfen: {0}'.format(repr(sfen)))
                    previous_was_digit = False
                    previous_was_plus = True
                elif c.lower() in ['p', 'l', 'n', 's', 'g', 'b', 'r', 'k']:
                    field_sum += 1
                    if previous_was_plus and (c.lower() == 'g' or c.lower() == 'k'):
                      raise ValueError('Gold and King cannot promote in position part of sfen: {0}')
                    previous_was_digit = False
                    previous_was_plus = False
                else:
                    raise ValueError('invalid character in position part of sfen: {0}'.format(repr(sfen)))

            if field_sum != 9:
                raise ValueError('expected 9 columns per row in position part of sfen: {0}'.format(repr(sfen)))

        # Check that the turn part is valid.
        if not parts[1] in ['b', 'w']:
            raise ValueError("expected 'b' or 'w' for turn part of sfen: {0}".format(repr(sfen)))

        # Check pieces in hand is valid.
        # TODO: implement with checking parts[2]

        # Check that the fullmove number part is valid.
        # 0 is allowed for compability but later replaced with 1.
        if int(parts[3]) < 0:
            raise ValueError('fullmove number must be positive: {0}'.format(repr(sfen)))

        # Clear board.
        self.clear()

        # Put pieces on the board.
        square_index = 0
        previous_was_plus = False
        for c in parts[0]:
            if c in ['1', '2', '3', '4', '5', '6', '7', '8', '9']:
                square_index += int(c)
            elif c == '+':
                previous_was_plus = True
            elif c == '/':
                pass
            else:
                piece_symbol = c
                if previous_was_plus:
                  piece_symbol = '+' + piece_symbol
                self.set_piece_at(square_index, Piece.from_symbol(piece_symbol))
                square_index += 1
                previous_was_plus = False

        # Set the turn.
        if parts[1] == 'w':
            self.turn = WHITE
        else:
            self.turn = BLACK

        # Set the pieces in hand
        self.pieces_in_hand = [collections.Counter(), collections.Counter()]
        if parts[2] != '-':
            piece_count = 0
            for c in parts[2]:
                if c in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']:
                    piece_count *= 10
                    piece_count += int(c)
                else:
                    piece = Piece.from_symbol(c)
                    if piece_count == 0:
                        piece_count = 1
                    self.add_piece_into_hand(piece.piece_type, piece.color, piece_count)
                    piece_count = 0

        # Set the mover counters.
        self.move_number = int(parts[3]) or 1

        # Reset the transposition table.
        self.transpositions = collections.Counter((self.zobrist_hash(), ))
def set_sfen(self, sfen):
        '''
        Parses a SFEN and sets the position from it.
        Rasies `ValueError` if the SFEN string is invalid.
        '''
        # Ensure there are six parts.
        parts = sfen.split()
        if len(parts) != 4:
            raise ValueError('sfen string should consist of 6 parts: {0}'.format(repr(sfen)))

        # Ensure the board part is valid.
        rows = parts[0].split('/')
        if len(rows) != 9:
            raise ValueError('expected 9 rows in position part of sfen: {0}'.format(repr(sfen)))

        # Validate each row.
        for row in rows:
            field_sum = 0
            previous_was_digit = False
            previous_was_plus = False

            for c in row:
                if c in ['1', '2', '3', '4', '5', '6', '7', '8', '9']:
                    if previous_was_digit:
                        raise ValueError('two subsequent digits in position part of sfen: {0}'.format(repr(sfen)))
                    if previous_was_plus:
                        raise ValueError('Cannot promote squares in position part of sfen: {0}'.format(repr(sfen)))
                    field_sum += int(c)
                    previous_was_digit = True
                    previous_was_plus = False
                elif c == '+':
                    if previous_was_plus:
                        raise ValueError('Double promotion prefixes in position part of sfen: {0}'.format(repr(sfen)))
                    previous_was_digit = False
                    previous_was_plus = True
                elif c.lower() in ['p', 'l', 'n', 's', 'g', 'b', 'r', 'k']:
                    field_sum += 1
                    if previous_was_plus and (c.lower() == 'g' or c.lower() == 'k'):
                      raise ValueError('Gold and King cannot promote in position part of sfen: {0}')
                    previous_was_digit = False
                    previous_was_plus = False
                else:
                    raise ValueError('invalid character in position part of sfen: {0}'.format(repr(sfen)))

            if field_sum != 9:
                raise ValueError('expected 9 columns per row in position part of sfen: {0}'.format(repr(sfen)))

        # Check that the turn part is valid.
        if not parts[1] in ['b', 'w']:
            raise ValueError("expected 'b' or 'w' for turn part of sfen: {0}".format(repr(sfen)))

        # Check pieces in hand is valid.
        # TODO: implement with checking parts[2]

        # Check that the fullmove number part is valid.
        # 0 is allowed for compability but later replaced with 1.
        if int(parts[3]) < 0:
            raise ValueError('fullmove number must be positive: {0}'.format(repr(sfen)))

        # Clear board.
        self.clear()

        # Put pieces on the board.
        square_index = 0
        previous_was_plus = False
        for c in parts[0]:
            if c in ['1', '2', '3', '4', '5', '6', '7', '8', '9']:
                square_index += int(c)
            elif c == '+':
                previous_was_plus = True
            elif c == '/':
                pass
            else:
                piece_symbol = c
                if previous_was_plus:
                  piece_symbol = '+' + piece_symbol
                self.set_piece_at(square_index, Piece.from_symbol(piece_symbol))
                square_index += 1
                previous_was_plus = False

        # Set the turn.
        if parts[1] == 'w':
            self.turn = WHITE
        else:
            self.turn = BLACK

        # Set the pieces in hand
        self.pieces_in_hand = [collections.Counter(), collections.Counter()]
        if parts[2] != '-':
            piece_count = 0
            for c in parts[2]:
                if c in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']:
                    piece_count *= 10
                    piece_count += int(c)
                else:
                    piece = Piece.from_symbol(c)
                    if piece_count == 0:
                        piece_count = 1
                    self.add_piece_into_hand(piece.piece_type, piece.color, piece_count)
                    piece_count = 0

        # Set the mover counters.
        self.move_number = int(parts[3]) or 1

        # Reset the transposition table.
        self.transpositions = collections.Counter((self.zobrist_hash(), ))
Parses a SFEN and sets the position from it.
        Rasies `ValueError` if the SFEN string is invalid.