Exemple #1
0
    def applyFen(self, fenstr):
        """ Applies the fenstring to the board.
            If the string is not properly
            written a SyntaxError will be raised, having its message ending in
            Pos(%d) specifying the string index of the problem.
            if an error is found, no changes will be made to the board. """

        assert not self.fen_was_applied, "The applyFen() method can be used on new LBoard objects only!"

        # Set board to empty on Black's turn (which Polyglot-hashes to 0)
        self.blocker = 0

        self.friends = [0, 0]
        self.kings = [-1, -1]
        self.boards = ([0] * 7, [0] * 7)

        self.enpassant = None  # cord which can be captured by enpassant or None
        self.color = BLACK
        self.castling = 0  # The castling availability in the position
        self.hasCastled = [False, False]
        self.fifty = 0  # A ply counter for the fifty moves rule
        self.plyCount = 0

        self.checked = None
        self.opchecked = None

        self.arBoard = [0] * 64

        self.hash = 0
        self.pawnhash = 0

        #  Data from the position's history:
        self.hist_move = []  # The move that was applied to get the position
        self.hist_tpiece = []
        # The piece the move captured, == EMPTY for normal moves
        self.hist_enpassant = []
        self.hist_castling = []
        self.hist_hash = []
        self.hist_fifty = []
        self.hist_checked = []
        self.hist_opchecked = []

        # piece counts
        self.pieceCount = ([0] * 7, [0] * 7)

        # initial cords of rooks and kings for castling in Chess960
        if self.variant == FISCHERRANDOMCHESS:
            self.ini_kings = [None, None]
            self.ini_rooks = ([None, None], [None, None])

        elif self.variant in (WILDCASTLECHESS, WILDCASTLESHUFFLECHESS):
            self.ini_kings = [None, None]
            self.fin_kings = ([None, None], [None, None])
            self.fin_rooks = ([None, None], [None, None])

        elif self.variant in DROP_VARIANTS:
            self.iniHouse()

        elif self.variant == ATOMICCHESS:
            self.iniAtomic()

        elif self.variant == CAMBODIANCHESS:
            self.iniCambodian()

            # Get information
        parts = fenstr.split()
        castChr = "-"
        epChr = "-"
        fiftyChr = "0"
        moveNoChr = "1"
        if STRICT_FEN and len(parts) != 6:
            raise SyntaxError(_("FEN needs 6 data fields. \n\n%s") % fenstr)
        elif len(parts) < 2:
            raise SyntaxError(
                _("FEN needs at least 2 data fields in fenstr. \n\n%s") %
                fenstr)
        elif len(parts) >= 6:
            pieceChrs, colChr, castChr, epChr, fiftyChr, moveNoChr = parts[:6]
        elif len(parts) == 5:
            pieceChrs, colChr, castChr, epChr, fiftyChr = parts
        elif len(parts) == 4:
            if parts[2].isdigit() and parts[3].isdigit():
                # xboard FEN usage for asian variants
                pieceChrs, colChr, fiftyChr, moveNoChr = parts
            else:
                pieceChrs, colChr, castChr, epChr = parts
        elif len(parts) == 3:
            pieceChrs, colChr, castChr = parts
        else:
            pieceChrs, colChr = parts

        # Try to validate some information
        # TODO: This should be expanded and perhaps moved

        slashes = pieceChrs.count("/")
        if slashes < 7:
            raise SyntaxError(
                _("Needs 7 slashes in piece placement field. \n\n%s") % fenstr)

        if not colChr.lower() in ("w", "b"):
            raise SyntaxError(
                _("Active color field must be one of w or b. \n\n%s") % fenstr)

        if castChr != "-":
            for Chr in castChr:
                valid_chars = "ABCDEFGHKQ" if self.variant == FISCHERRANDOMCHESS else "KQ"
                if Chr.upper() not in valid_chars:
                    if self.variant == CAMBODIANCHESS:
                        pass
                        # sjaakii uses DEde in cambodian starting fen to indicate
                        # that queens and kings are virgins (not moved yet)
                    else:
                        raise SyntaxError(
                            _("Castling availability field is not legal. \n\n%s"
                              ) % fenstr)

        if epChr != "-" and epChr not in cordDic:
            raise SyntaxError(
                _("En passant cord is not legal. \n\n%s") % fenstr)

        # Parse piece placement field
        promoted = False
        # if there is a holding within [] we change it to BFEN style first
        if pieceChrs.endswith("]"):
            pieceChrs = pieceChrs[:-1].replace("[", "/")
        for r, rank in enumerate(pieceChrs.split("/")):
            cord = (7 - r) * 8
            for char in rank:
                if r > 7:
                    # After the 8.rank BFEN can contain holdings (captured pieces)
                    # "~" after a piece letter denotes promoted piece
                    if r == 8 and self.variant in DROP_VARIANTS:
                        color = char.islower() and BLACK or WHITE
                        piece = chrU2Sign[char.upper()]
                        self.holding[color][piece] += 1
                        self.hash ^= holdingHash[color][piece][
                            self.holding[color][piece]]
                        continue
                    else:
                        break

                if char.isdigit():
                    cord += int(char)
                elif char == "~":
                    promoted = True
                else:
                    color = char.islower() and BLACK or WHITE
                    piece = chrU2Sign[char.upper()]
                    self._addPiece(cord, piece, color)
                    self.pieceCount[color][piece] += 1

                    if self.variant in DROP_VARIANTS and promoted:
                        self.promoted[cord] = 1
                        promoted = False

                    if self.variant == CAMBODIANCHESS:
                        if piece == KING and self.kings[
                                color] != self.ini_kings[color]:
                            self.is_first_move[KING][color] = False
                        if piece == QUEEN and cord != self.ini_queens[color]:
                            self.is_first_move[QUEEN][color] = False

                    cord += 1

            if self.variant == FISCHERRANDOMCHESS:
                # Save ranks fo find outermost rooks
                # if KkQq was used in castling rights
                if r == 0:
                    rank8 = rank
                elif r == 7:
                    rank1 = rank

        # Parse active color field

        if colChr.lower() == "w":
            self.setColor(WHITE)
        else:
            self.setColor(BLACK)

        # Parse castling availability

        castling = 0
        for char in castChr:
            if self.variant == FISCHERRANDOMCHESS:
                if char in reprFile:
                    if char < reprCord[self.kings[BLACK]][0]:
                        castling |= B_OOO
                        self.ini_rooks[1][0] = reprFile.index(char) + 56
                    else:
                        castling |= B_OO
                        self.ini_rooks[1][1] = reprFile.index(char) + 56
                elif char in [c.upper() for c in reprFile]:
                    if char < reprCord[self.kings[WHITE]][0].upper():
                        castling |= W_OOO
                        self.ini_rooks[0][0] = reprFile.index(char.lower())
                    else:
                        castling |= W_OO
                        self.ini_rooks[0][1] = reprFile.index(char.lower())
                elif char == "K":
                    castling |= W_OO
                    self.ini_rooks[0][1] = rank1.rfind('R')
                elif char == "Q":
                    castling |= W_OOO
                    self.ini_rooks[0][0] = rank1.find('R')
                elif char == "k":
                    castling |= B_OO
                    self.ini_rooks[1][1] = rank8.rfind('r') + 56
                elif char == "q":
                    castling |= B_OOO
                    self.ini_rooks[1][0] = rank8.find('r') + 56
            else:
                if char == "K":
                    castling |= W_OO
                elif char == "Q":
                    castling |= W_OOO
                elif char == "k":
                    castling |= B_OO
                elif char == "q":
                    castling |= B_OOO

        if self.variant in (WILDCASTLECHESS, WILDCASTLESHUFFLECHESS,
                            FISCHERRANDOMCHESS):
            self.ini_kings[WHITE] = self.kings[WHITE]
            self.ini_kings[BLACK] = self.kings[BLACK]
            if self.variant in (WILDCASTLECHESS, WILDCASTLESHUFFLECHESS):
                if self.ini_kings[WHITE] == D1 and self.ini_kings[BLACK] == D8:
                    self.fin_kings = ([B1, F1], [B8, F8])
                    self.fin_rooks = ([C1, E1], [C8, E8])
                elif self.ini_kings[WHITE] == D1:
                    self.fin_kings = ([B1, F1], [C8, G8])
                    self.fin_rooks = ([C1, E1], [D8, F8])
                elif self.ini_kings[BLACK] == D8:
                    self.fin_kings = ([C1, G1], [B8, F8])
                    self.fin_rooks = ([D1, F1], [C8, E8])
                else:
                    self.fin_kings = ([C1, G1], [C8, G8])
                    self.fin_rooks = ([D1, F1], [D8, F8])

        self.setCastling(castling)

        # Parse en passant target sqaure

        if epChr == "-":
            self.setEnpassant(None)
        else:
            self.setEnpassant(cordDic[epChr])

        # Parse halfmove clock field

        if fiftyChr.isdigit():
            self.fifty = int(fiftyChr)
        else:
            self.fifty = 0

        # Parse fullmove number

        if moveNoChr.isdigit():
            movenumber = max(int(moveNoChr), 1) * 2 - 2
            if self.color == BLACK:
                movenumber += 1
            self.plyCount = movenumber
        else:
            self.plyCount = 1

        self.fen_was_applied = True
Exemple #2
0
    def applyFen(self, fenstr):
        """ Applies the fenstring to the board.
            If the string is not properly
            written a SyntaxError will be raised, having its message ending in
            Pos(%d) specifying the string index of the problem.
            if an error is found, no changes will be made to the board. """

        assert not self.fen_was_applied, "The applyFen() method can be used on new LBoard objects only!"

        # Set board to empty on Black's turn (which Polyglot-hashes to 0)
        self.blocker = 0

        self.friends = [0] * 2
        self.kings = [-1] * 2
        self.boards = [[0] * 7 for i in range(2)]

        self.enpassant = None  # cord which can be captured by enpassant or None
        self.color = BLACK
        self.castling = 0  # The castling availability in the position
        self.hasCastled = [False, False]
        self.fifty = 0  # A ply counter for the fifty moves rule
        self.plyCount = 0

        self.checked = None
        self.opchecked = None

        self.arBoard = [0] * 64

        self.hash = 0
        self.pawnhash = 0

        #  Data from the position's history:
        self.hist_move = []  # The move that was applied to get the position
        self.hist_tpiece = [
        ]  # The piece the move captured, == EMPTY for normal moves
        self.hist_enpassant = []
        self.hist_castling = []
        self.hist_hash = []
        self.hist_fifty = []
        self.hist_checked = []
        self.hist_opchecked = []

        # piece counts
        self.pieceCount = [[0] * 7, [0] * 7]

        # initial cords of rooks and kings for castling in Chess960
        if self.variant == FISCHERRANDOMCHESS:
            self.ini_kings = [None, None]
            self.ini_rooks = ([None, None], [None, None])

        elif self.variant in (WILDCASTLECHESS, WILDCASTLESHUFFLECHESS):
            self.ini_kings = [None, None]
            self.fin_kings = ([None, None], [None, None])
            self.fin_rooks = ([None, None], [None, None])

        elif self.variant in DROP_VARIANTS:
            self.iniHouse()

        elif self.variant == ATOMICCHESS:
            self.iniAtomic()

        elif self.variant == CAMBODIANCHESS:
            self.iniCambodian()

            # Get information
        parts = fenstr.split()
        castChr = "-"
        epChr = "-"
        fiftyChr = "0"
        moveNoChr = "1"
        if STRICT_FEN and len(parts) != 6:
            raise SyntaxError(_("FEN needs 6 data fields. \n\n%s") % fenstr)
        elif len(parts) < 2:
            raise SyntaxError(
                _("FEN needs at least 2 data fields in fenstr. \n\n%s") %
                fenstr)
        elif len(parts) >= 6:
            pieceChrs, colChr, castChr, epChr, fiftyChr, moveNoChr = parts[:6]
        elif len(parts) == 5:
            pieceChrs, colChr, castChr, epChr, fiftyChr = parts
        elif len(parts) == 4:
            if parts[2].isdigit() and parts[3].isdigit():
                # xboard FEN usage for asian variants
                pieceChrs, colChr, fiftyChr, moveNoChr = parts
            else:
                pieceChrs, colChr, castChr, epChr = parts
        elif len(parts) == 3:
            pieceChrs, colChr, castChr = parts
        else:
            pieceChrs, colChr = parts

        # Try to validate some information
        # TODO: This should be expanded and perhaps moved

        slashes = pieceChrs.count("/")
        if slashes < 7:
            raise SyntaxError(
                _("Needs 7 slashes in piece placement field. \n\n%s") % fenstr)

        if not colChr.lower() in ("w", "b"):
            raise SyntaxError(
                _("Active color field must be one of w or b. \n\n%s") % fenstr)

        if castChr != "-":
            for Chr in castChr:
                valid_chars = "ABCDEFGHKQ" if self.variant == FISCHERRANDOMCHESS else "KQ"
                if Chr.upper() not in valid_chars:
                    if self.variant == CAMBODIANCHESS:
                        pass
                        # sjaakii uses DEde in cambodian starting fen to indicate
                        # that queens and kings are virgins (not moved yet)
                    else:
                        raise SyntaxError(_("Castling availability field is not legal. \n\n%s")
                                          % fenstr)

        if epChr != "-" and epChr not in cordDic:
            raise SyntaxError(_("En passant cord is not legal. \n\n%s") %
                              fenstr)

        # Parse piece placement field
        promoted = False
        # if there is a holding within [] we change it to BFEN style first
        if pieceChrs.endswith("]"):
            pieceChrs = pieceChrs[:-1].replace("[", "/")
        for r, rank in enumerate(pieceChrs.split("/")):
            cord = (7 - r) * 8
            for char in rank:
                if r > 7:
                    # After the 8.rank BFEN can contain holdings (captured pieces)
                    # "~" after a piece letter denotes promoted piece
                    if r == 8 and self.variant in DROP_VARIANTS:
                        color = char.islower() and BLACK or WHITE
                        piece = chrU2Sign[char.upper()]
                        self.holding[color][piece] += 1
                        continue
                    else:
                        break

                if char.isdigit():
                    cord += int(char)
                elif char == "~":
                    promoted = True
                else:
                    color = char.islower() and BLACK or WHITE
                    piece = chrU2Sign[char.upper()]
                    self._addPiece(cord, piece, color)
                    self.pieceCount[color][piece] += 1

                    if self.variant in DROP_VARIANTS and promoted:
                        self.promoted[cord] = 1
                        promoted = False

                    if self.variant == CAMBODIANCHESS:
                        if piece == KING and self.kings[
                                color] != self.ini_kings[color]:
                            self.is_first_move[KING][color] = False
                        if piece == QUEEN and cord != self.ini_queens[color]:
                            self.is_first_move[QUEEN][color] = False

                    cord += 1

            if self.variant == FISCHERRANDOMCHESS:
                # Save ranks fo find outermost rooks
                # if KkQq was used in castling rights
                if r == 0:
                    rank8 = rank
                elif r == 7:
                    rank1 = rank

        # Parse active color field

        if colChr.lower() == "w":
            self.setColor(WHITE)
        else:
            self.setColor(BLACK)

        # Parse castling availability

        castling = 0
        for char in castChr:
            if self.variant == FISCHERRANDOMCHESS:
                if char in reprFile:
                    if char < reprCord[self.kings[BLACK]][0]:
                        castling |= B_OOO
                        self.ini_rooks[1][0] = reprFile.index(char) + 56
                    else:
                        castling |= B_OO
                        self.ini_rooks[1][1] = reprFile.index(char) + 56
                elif char in [c.upper() for c in reprFile]:
                    if char < reprCord[self.kings[WHITE]][0].upper():
                        castling |= W_OOO
                        self.ini_rooks[0][0] = reprFile.index(char.lower())
                    else:
                        castling |= W_OO
                        self.ini_rooks[0][1] = reprFile.index(char.lower())
                elif char == "K":
                    castling |= W_OO
                    self.ini_rooks[0][1] = rank1.rfind('R')
                elif char == "Q":
                    castling |= W_OOO
                    self.ini_rooks[0][0] = rank1.find('R')
                elif char == "k":
                    castling |= B_OO
                    self.ini_rooks[1][1] = rank8.rfind('r') + 56
                elif char == "q":
                    castling |= B_OOO
                    self.ini_rooks[1][0] = rank8.find('r') + 56
            else:
                if char == "K":
                    castling |= W_OO
                elif char == "Q":
                    castling |= W_OOO
                elif char == "k":
                    castling |= B_OO
                elif char == "q":
                    castling |= B_OOO

        if self.variant in (WILDCASTLECHESS, WILDCASTLESHUFFLECHESS,
                            FISCHERRANDOMCHESS):
            self.ini_kings[WHITE] = self.kings[WHITE]
            self.ini_kings[BLACK] = self.kings[BLACK]
            if self.variant in (WILDCASTLECHESS, WILDCASTLESHUFFLECHESS):
                if self.ini_kings[WHITE] == D1 and self.ini_kings[BLACK] == D8:
                    self.fin_kings = ([B1, F1], [B8, F8])
                    self.fin_rooks = ([C1, E1], [C8, E8])
                elif self.ini_kings[WHITE] == D1:
                    self.fin_kings = ([B1, F1], [C8, G8])
                    self.fin_rooks = ([C1, E1], [D8, F8])
                elif self.ini_kings[BLACK] == D8:
                    self.fin_kings = ([C1, G1], [B8, F8])
                    self.fin_rooks = ([D1, F1], [C8, E8])
                else:
                    self.fin_kings = ([C1, G1], [C8, G8])
                    self.fin_rooks = ([D1, F1], [D8, F8])

        self.setCastling(castling)

        # Parse en passant target sqaure

        if epChr == "-":
            self.setEnpassant(None)
        else:
            self.setEnpassant(cordDic[epChr])

        # Parse halfmove clock field

        if fiftyChr.isdigit():
            self.fifty = int(fiftyChr)
        else:
            self.fifty = 0

        # Parse fullmove number

        if moveNoChr.isdigit():
            movenumber = max(int(moveNoChr), 1) * 2 - 2
            if self.color == BLACK:
                movenumber += 1
            self.plyCount = movenumber
        else:
            self.plyCount = 1

        self.fen_was_applied = True