Ejemplo n.º 1
0
    def test_getstatus1(self):
        """Testing bare black king is not draw in Atomic variant"""

        board = AtomicBoard(setup=FEN2)
        board = board.move(parseSAN(board, 'Qxc2'))
        print(board)
        self.assertEqual(getStatus(board), (BLACKWON, WON_KINGEXPLODE))
Ejemplo n.º 2
0
    def loadToModel(self, gameno, position, model=None):
        if not model:
            model = GameModel()

        # We have to set full move number to 1 to make sure LBoard and GameModel
        # are synchronized.
        #fenlist = self.games[gameno].split(" ")
        #if len(fenlist) == 6:
        #    fen = " ".join(fenlist[:5]) + " 1"
        fen = self.games[gameno]
        try:
            board = model.variant(setup=fen)
        except SyntaxError as err:
            board = model.variant()
            raise LoadingError(
                _("The game can't be loaded, because of an error parsing FEN"),
                err.args[0])

        model.boards = [board]
        model.variations = [model.boards]
        model.moves = []
        if model.status == WAITING_TO_START:
            status, reason = getStatus(model.boards[-1])
            if status in (BLACKWON, WHITEWON, DRAW):
                model.status, model.reason = status, reason
        return model
Ejemplo n.º 3
0
    def loadToModel(self, rec, position, model=None):
        if not model:
            model = GameModel()

        if self.fen_is_string:
            rec = self.games[0]

        if "Variant" in rec:
            model.variant = FischerandomBoard

        fen = self.games[0]["FEN"]
        try:
            board = model.variant(setup=fen)
        except SyntaxError as err:
            board = model.variant()
            raise LoadingError(
                _("The game can't be loaded, because of an error parsing FEN"),
                err.args[0])

        model.boards = [board]
        model.variations = [model.boards]
        model.moves = []
        if model.status == WAITING_TO_START:
            status, reason = getStatus(model.boards[-1])
            if status in (BLACKWON, WHITEWON, DRAW):
                model.status, model.reason = status, reason
        return model
Ejemplo n.º 4
0
    def test_getstatus1(self):
        """Testing bare black king is not draw in Atomic variant"""

        board = AtomicBoard(setup=FEN2)
        board = board.move(parseSAN(board, 'Qxc2'))
        print(board)
        self.assertEqual(getStatus(board), (BLACKWON, WON_KINGEXPLODE))
Ejemplo n.º 5
0
    def test1(self):
        """Testing both king goes to 8.row draw in racingkings variant"""

        board = RacingKingsBoard(setup=FEN)
        board = board.move(parseSAN(board, 'Kh8'))
        print(board)
        # White king reached 8th row, but this is not a win
        # because black can reach 8th row also with hes next move
        self.assertEqual(getStatus(board), (RUNNING, UNKNOWN_REASON))

        self.assertTrue(validate(board, parseSAN(board, 'Kb8')))
        self.assertTrue(not validate(board, parseSAN(board, 'Kd8')))

        board = board.move(parseSAN(board, 'Kb8'))
        print(board)
        self.assertEqual(getStatus(board), (DRAW, DRAW_KINGSINEIGHTROW))
Ejemplo n.º 6
0
    def loadToModel(self, rec, position, model=None):
        if not model:
            model = GameModel()

        if self.fen_is_string:
            rec = self.games[0]

        if isinstance(rec, dict) and "Variant" in rec:
            model.variant = FischerandomBoard

        fen = self.games[0]["FEN"]
        try:
            board = model.variant(setup=fen)
        except SyntaxError as err:
            board = model.variant()
            raise LoadingError(
                _("The game can't be loaded, because of an error parsing FEN"),
                err.args[0])

        model.boards = [board]
        model.variations = [model.boards]
        model.moves = []
        if model.status == WAITING_TO_START:
            status, reason = getStatus(model.boards[-1])
            if status in (BLACKWON, WHITEWON, DRAW):
                model.status, model.reason = status, reason
        return model
Ejemplo n.º 7
0
    def loadToModel(self, gameno, position, model=None):
        if not model:
            model = GameModel()

        # We have to set full move number to 1 to make sure LBoard and GameModel
        # are synchronized.
        # fenlist = self.games[gameno].split(" ")
        # if len(fenlist) == 6:
        #    fen = " ".join(fenlist[:5]) + " 1"
        fen = self.games[gameno]
        try:
            board = model.variant(setup=fen)
        except SyntaxError as err:
            board = model.variant()
            raise LoadingError(
                _("The game can't be loaded, because of an error parsing FEN"),
                err.args[0])

        model.boards = [board]
        model.variations = [model.boards]
        model.moves = []
        if model.status == WAITING_TO_START:
            status, reason = getStatus(model.boards[-1])
            if status in (BLACKWON, WHITEWON, DRAW):
                model.status, model.reason = status, reason
        return model
Ejemplo n.º 8
0
    def loadToModel(self, rec, position, model=None):
        if not model:
            model = GameModel()

        if "Variant" in rec:
            model.variant = FischerandomBoard

        fieldlist = rec["FEN"].split(" ")
        if len(fieldlist) == 4:
            fen = rec["FEN"]
            opcodestr = ""

        elif len(fieldlist) > 4:
            fen = " ".join(fieldlist[:4])
            opcodestr = " ".join(fieldlist[4:])

        else:
            raise LoadingError("EPD string can not have less than 4 field")

        opcodes = {}
        for opcode in map(str.strip, opcodestr.split(";")):
            space = opcode.find(" ")
            if space == -1:
                opcodes[opcode] = True
            else:
                opcodes[opcode[:space]] = opcode[space + 1:]

        if "hmvc" in opcodes:
            fen += " " + opcodes["hmvc"]
        else:
            fen += " 0"

        if "fmvn" in opcodes:
            fen += " " + opcodes["fmvn"]
        else:
            fen += " 1"

        model.boards = [model.variant(setup=fen)]
        model.variations = [model.boards]
        model.status = WAITING_TO_START

        # rc is kinda broken
        # if "rc" in opcodes:
        #    model.boards[0].board.rc = int(opcodes["rc"])

        if "resign" in opcodes:
            if fieldlist[1] == "w":
                model.status = BLACKWON
            else:
                model.status = WHITEWON
            model.reason = WON_RESIGN

        if model.status == WAITING_TO_START:
            status, reason = getStatus(model.boards[-1])
            if status in (BLACKWON, WHITEWON, DRAW):
                model.status, model.reason = status, reason

        return model
Ejemplo n.º 9
0
    def _searchNow(self, ponderhit=False):
        log.debug("_searchNow: self.needBestmove=%s ponderhit=%s self.board=%s" % (
            self.needBestmove, ponderhit, self.board), extra={"task": self.defname})

        commands = []

        if ponderhit:
            commands.append("ponderhit")

        elif self.mode == NORMAL:
            commands.append("position %s" % self.uciPosition)
            if self.strength <= 3:
                commands.append("go depth %d" % self.strength)
            else:
                if self.moves > 0:
                    commands.append("go wtime %d winc %d btime %d binc %d movestogo %s" % (
                                    self.wtime, self.incr, self.btime, self.incr, self.moves))
                else:
                    commands.append("go wtime %d winc %d btime %d binc %d" % (
                                    self.wtime, self.incr, self.btime, self.incr))

        else:
            print("stop", file=self.engine)

            if self.mode == INVERSE_ANALYZING:
                if self.board.board.opIsChecked():
                    # Many engines don't like positions able to take down enemy
                    # king. Therefore we just return the "kill king" move
                    # automaticaly
                    self.emit("analyze", [([toAN(
                        self.board, getMoveKillingKing(self.board))], MATE_VALUE - 1, "")])
                    return
                commands.append("position fen %s" % self.board.asFen())
            else:
                commands.append("position %s" % self.uciPosition)

            # commands.append("go infinite")
            move_time = int(conf.get("max_analysis_spin", 3)) * 1000
            commands.append("go movetime %s" % move_time)

        if self.hasOption("MultiPV") and self.multipvSetting > 1:
            self.multipvExpected = min(self.multipvSetting,
                                       legalMoveCount(self.board))
        else:
            self.multipvExpected = 1
        self.analysis = [None] * self.multipvExpected

        if self.needBestmove:
            self.commands.append(commands)
            log.debug("_searchNow: self.needBestmove==True, appended to self.commands=%s" %
                      self.commands, extra={"task": self.defname})
        else:
            for command in commands:
                print(command, file=self.engine)
            if getStatus(self.board)[
                    1] != WON_MATE:  # XXX This looks fishy.
                self.needBestmove = True
                self.readyForStop = True
Ejemplo n.º 10
0
    def loadToModel(self, rec, position, model=None):
        if not model:
            model = GameModel()

        if "Variant" in rec:
            model.variant = FischerandomBoard

        fieldlist = rec["FEN"].split(" ")
        if len(fieldlist) == 4:
            fen = rec["FEN"]
            opcodestr = ""

        elif len(fieldlist) > 4:
            fen = " ".join(fieldlist[:4])
            opcodestr = " ".join(fieldlist[4:])

        else:
            raise LoadingError("EPD string can not have less than 4 field")

        opcodes = {}
        for opcode in map(str.strip, opcodestr.split(";")):
            space = opcode.find(" ")
            if space == -1:
                opcodes[opcode] = True
            else:
                opcodes[opcode[:space]] = opcode[space + 1:]

        if "hmvc" in opcodes:
            fen += " " + opcodes["hmvc"]
        else:
            fen += " 0"

        if "fmvn" in opcodes:
            fen += " " + opcodes["fmvn"]
        else:
            fen += " 1"

        model.boards = [model.variant(setup=fen)]
        model.variations = [model.boards]
        model.status = WAITING_TO_START

        # rc is kinda broken
        # if "rc" in opcodes:
        #    model.boards[0].board.rc = int(opcodes["rc"])

        if "resign" in opcodes:
            if fieldlist[1] == "w":
                model.status = BLACKWON
            else:
                model.status = WHITEWON
            model.reason = WON_RESIGN

        if model.status == WAITING_TO_START:
            status, reason = getStatus(model.boards[-1])
            if status in (BLACKWON, WHITEWON, DRAW):
                model.status, model.reason = status, reason

        return model
Ejemplo n.º 11
0
    def test_getstatus2(self):
        """Testing bare white king is not draw in Atomic variant"""

        board = AtomicBoard(setup=FEN3)
        self.assertTrue(not validate(board, parseSAN(board, 'Kxg7')))
        self.assertTrue(not validate(board, parseSAN(board, 'Kg8')))
        self.assertTrue(not validate(board, parseSAN(board, 'Kh7')))
        print(board)
        self.assertEqual(getStatus(board), (DRAW, DRAW_STALEMATE))
Ejemplo n.º 12
0
    def test_getstatus2(self):
        """Testing bare white king is not draw in Atomic variant"""

        board = AtomicBoard(setup=FEN3)
        self.assertTrue(not validate(board, parseSAN(board, 'Kxg7')))
        self.assertTrue(not validate(board, parseSAN(board, 'Kg8')))
        self.assertTrue(not validate(board, parseSAN(board, 'Kh7')))
        print(board)
        self.assertEqual(getStatus(board), (DRAW, DRAW_STALEMATE))
Ejemplo n.º 13
0
    def _searchNow (self, ponderhit=False):
        log.debug("_searchNow: self.needBestmove=%s ponderhit=%s self.board=%s\n" % \
            (self.needBestmove, ponderhit, self.board), self.defname)

        with self.moveLock:
            commands = []
            
            if ponderhit:
                commands.append("ponderhit")
                
            elif self.mode == NORMAL:
                commands.append("position %s" % self.uciPosition)
                if self.strength <= 3:
                    commands.append("go depth %d" % self.strength)
                else:
                    commands.append("go wtime %d winc %d btime %d binc %d" % \
                                    (self.wtime, self.incr, self.btime, self.incr))
                
            else:
                print >> self.engine, "stop"
                
                if self.mode == INVERSE_ANALYZING:
                    if self.board.board.opIsChecked():
                        # Many engines don't like positions able to take down enemy
                        # king. Therefore we just return the "kill king" move
                        # automaticaly
                        #self.emit("analyze", [([getMoveKillingKing(self.board)], MATE_VALUE-1)])
                        return
                    commands.append("position fen %s" % self.board.asFen())
                else:
                    commands.append("position %s" % self.uciPosition)

                commands.append("go infinite")
            
            if self.hasOption("MultiPV") and self.multipvSetting > 1:
                self.multipvExpected = min(self.multipvSetting, legalMoveCount(self.board))
            else:
                self.multipvExpected = 1
            self.analysis = [None] * self.multipvExpected
            
            if self.needBestmove:
                self.commands.append(commands)
                log.debug("_searchNow: self.needBestmove==True, appended to self.commands=%s\n" % \
                    self.commands, self.defname)
            else:
                for command in commands:
                    print >> self.engine, command
                if getStatus(self.board)[1] != WON_MATE: # XXX This looks fishy.
                    self.needBestmove = True
                    self.readyForStop = True
Ejemplo n.º 14
0
def check_if_game_over(board: Board, game_id: int) -> str:
    winner = ""
    status, _ = getStatus(board)
    if status == WHITEWON:
        winner = WHITE_STR
    elif status == BLACKWON:
        winner = BLACK_STR

    if winner != "":
        game = Games.objects.get(id=game_id)
        game.ongoing = False
        game.save()

    return winner
Ejemplo n.º 15
0
 def loadToModel (self, gameno, position, model=None):
     if not model: model = GameModel()
     
     # We have to set full move number to 1 to make sure LBoard and GameModel
     # are synchronized.
     #fenlist = self.games[gameno].split(" ")
     #if len(fenlist) == 6:
     #    fen = " ".join(fenlist[:5]) + " 1" 
     fen = self.games[gameno]
     
     model.boards = [model.variant.board(setup=fen)]
     if model.status == WAITING_TO_START:
         model.status, model.reason = getStatus(model.boards[-1])
     
     return model
Ejemplo n.º 16
0
    def game_changed(self, gamemodel, ply):
        if gamemodel.practice_game:
            if len(gamemodel.moves) % 2 == 0:
                # engine moved, we can enable retry
                self.set_response_sensitive(RETRY, True)
                return

            # print(gamemodel.hint, repr(gamemodel.moves[-1]))
            status, reason = getStatus(gamemodel.boards[-1])

            if status in UNDOABLE_STATES:
                self.get_next_puzzle()
            elif gamemodel.hint and gamemodel.hint != repr(
                    gamemodel.moves[-1]):
                self.retry()
            else:
                self.your_turn()
Ejemplo n.º 17
0
    def _searchNow(self, ponderhit=False):
        log.debug("_searchNow: self.needBestmove=%s ponderhit=%s self.board=%s\n" % \
            (self.needBestmove, ponderhit, self.board), self.defname)
        with self.moveLock:
            commands = []

            if ponderhit:
                commands.append("ponderhit")

            elif self.mode == NORMAL:
                commands.append("position fen %s" % self.board.asFen())
                if self.strength <= 3:
                    commands.append("go depth %d" % self.strength)
                else:
                    commands.append("go wtime %d btime %d winc %d binc %d" % \
                                    (self.wtime, self.btime, self.incr, self.incr))

            else:
                if self.mode == INVERSE_ANALYZING:
                    if self.board.board.opIsChecked():
                        # Many engines don't like positions able to take down enemy
                        # king. Therefore we just return the "kill king" move
                        # automaticaly
                        self.emit("analyze", [getMoveKillingKing(self.board)],
                                  MATE_VALUE - 1)
                        return

                print >> self.engine, "stop"
                if self.board.asFen() == FEN_START:
                    commands.append("position startpos")
                else:
                    commands.append("position fen %s" % self.board.asXFen())
                commands.append("go infinite")

            if self.needBestmove:
                self.commands.append(commands)
                log.debug("_searchNow: self.needBestmove==True, appended to self.commands=%s\n" % \
                    self.commands, self.defname)
            else:
                for command in commands:
                    print >> self.engine, command
                if self.board.asFen() != FEN_START and getStatus(
                        self.board)[1] != WON_MATE:
                    self.needBestmove = True
                    self.readyForStop = True
Ejemplo n.º 18
0
 def loadToModel (self, gameno, position, model=None):
     if not model: model = GameModel()
     
     board = model.variant.board()
     for y,row in enumerate(self.games[gameno]):
         for x,letter in enumerate(reg2.findall(row)):
             if letter in entitydefs:
                 letter = entitydefs[letter]
             if letter not in piecesDia:
                 raise LoadingError (_("Couldn't load the diagram '%s'")%repr(letter))
             col, pie = piecesDia[letter]
             if pie != EMPTY:
                 board.addPiece(Cord(x,7-y), Piece(col,pie))
     
     model.boards = [board]
     if model.status == WAITING_TO_START:
         model.status, model.reason = getStatus(model.boards[-1])
     
     return model
Ejemplo n.º 19
0
 def _searchNow (self, ponderhit=False):
     log.debug("_searchNow: self.needBestmove=%s ponderhit=%s self.board=%s\n" % \
         (self.needBestmove, ponderhit, self.board), self.defname)
     with self.moveLock:
         commands = []
         
         if ponderhit:
             commands.append("ponderhit")
             
         elif self.mode == NORMAL:
             commands.append("position fen %s" % self.board.asFen())
             if self.strength <= 3:
                 commands.append("go depth %d" % self.strength)
             else:
                 commands.append("go wtime %d btime %d winc %d binc %d" % \
                                 (self.wtime, self.btime, self.incr, self.incr))
             
         else:
             if self.mode == INVERSE_ANALYZING:
                 if self.board.board.opIsChecked():
                     # Many engines don't like positions able to take down enemy
                     # king. Therefore we just return the "kill king" move
                     # automaticaly
                     self.emit("analyze", [getMoveKillingKing(self.board)], MATE_VALUE-1)
                     return
             
             print >> self.engine, "stop"
             if self.board.asFen() == FEN_START:
                 commands.append("position startpos")
             else:
                 commands.append("position fen %s" % self.board.asXFen())
             commands.append("go infinite")
         
         if self.needBestmove:
             self.commands.append(commands)
             log.debug("_searchNow: self.needBestmove==True, appended to self.commands=%s\n" % \
                 self.commands, self.defname)
         else:
             for command in commands:
                 print >> self.engine, command
             if self.board.asFen() != FEN_START and getStatus(self.board)[1] != WON_MATE:
                 self.needBestmove = True
                 self.readyForStop = True
Ejemplo n.º 20
0
    def test_getstatus3(self):
        """Testing possible to mate with the queen unaided in Atomic variant"""

        board = AtomicBoard(setup=FEN4)
        print(board)
        self.assertEqual(getStatus(board), (WHITEWON, WON_MATE))
Ejemplo n.º 21
0
    def loadToModel(self, rec, position=-1, model=None):
        """ Parse game text and load game record header tags to a GameModel object """

        if model is None:
            model = GameModel()

        if self.pgn_is_string:
            rec = self.games[0]

        # Load mandatory tags
        for tag in mandatory_tags:
            model.tags[tag] = rec[tag]

        # Load other tags
        for tag in ('WhiteElo', 'BlackElo', 'ECO', 'TimeControl', 'Annotator'):
            model.tags[tag] = rec[tag]

        if self.pgn_is_string:
            for tag in rec:
                if isinstance(rec[tag], str) and rec[tag]:
                    model.tags[tag] = rec[tag]
        else:
            model.info = self.tag_database.get_info(rec)
            extra_tags = self.tag_database.get_exta_tags(rec)
            for et in extra_tags:
                model.tags[et['tag_name']] = et['tag_value']

        if self.pgn_is_string:
            variant = rec["Variant"].capitalize()
        else:
            variant = self.get_variant(rec)

        if model.tags['TimeControl']:
            tc = parseTimeControlTag(model.tags['TimeControl'])
            if tc is not None:
                secs, gain, moves = tc
                model.timed = True
                model.timemodel.secs = secs
                model.timemodel.gain = gain
                model.timemodel.minutes = secs / 60
                model.timemodel.moves = moves
                for tag, color in (('WhiteClock', WHITE), ('BlackClock',
                                                           BLACK)):
                    if tag in model.tags:
                        try:
                            millisec = parseClockTimeTag(model.tags[tag])
                            # We need to fix when FICS reports negative clock time like this
                            # [TimeControl "180+0"]
                            # [WhiteClock "0:00:15.867"]
                            # [BlackClock "23:59:58.820"]
                            start_sec = (
                                millisec - 24 * 60 * 60 * 1000
                            ) / 1000. if millisec > 23 * 60 * 60 * 1000 else millisec / 1000.
                            model.timemodel.intervals[color][0] = start_sec
                        except ValueError:
                            raise LoadingError("Error parsing '%s'" % tag)
        fenstr = rec["FEN"]

        if variant:
            if variant not in name2variant:
                raise LoadingError("Unknown variant %s" % variant)

            model.tags["Variant"] = variant
            # Fixes for some non statndard Chess960 .pgn
            if (fenstr is not None) and variant == "Fischerandom":
                parts = fenstr.split()
                parts[0] = parts[0].replace(".", "/").replace("0", "")
                if len(parts) == 1:
                    parts.append("w")
                    parts.append("-")
                    parts.append("-")
                fenstr = " ".join(parts)

            model.variant = name2variant[variant]
            board = LBoard(model.variant.variant)
        else:
            model.variant = NormalBoard
            board = LBoard()

        if fenstr:
            try:
                board.applyFen(fenstr)
                model.tags["FEN"] = fenstr
            except SyntaxError as err:
                board.applyFen(FEN_EMPTY)
                raise LoadingError(
                    _("The game can't be loaded, because of an error parsing FEN"
                      ), err.args[0])
        else:
            board.applyFen(FEN_START)

        boards = [board]

        del model.moves[:]
        del model.variations[:]

        self.error = None
        movetext = self.get_movetext(rec)
        boards = self.parse_movetext(movetext, boards[0], position)

        # The parser built a tree of lboard objects, now we have to
        # create the high level Board and Move lists...

        for board in boards:
            if board.lastMove is not None:
                model.moves.append(Move(board.lastMove))

        self.has_emt = False
        self.has_eval = False

        def _create_board(model, node):
            if node.prev is None:
                # initial game board
                board = model.variant(setup=node.asFen(), lboard=node)
            else:
                move = Move(node.lastMove)
                try:
                    board = node.prev.pieceBoard.move(move, lboard=node)
                except Exception:
                    raise LoadingError(
                        _("Invalid move."),
                        "%s%s" % (move_count(node, black_periods=True), move))

            return board

        def walk(model, node, path):
            boards = path
            stack = []
            current = node

            while current is not None:
                board = _create_board(model, current)
                boards.append(board)
                stack.append(current)
                current = current.next
            else:
                model.variations.append(list(boards))

            while stack:
                current = stack.pop()
                boards.pop()
                for child in current.children:
                    if isinstance(child, list):
                        if len(child) > 1:
                            # non empty variation, go walk
                            walk(model, child[1], list(boards))
                    else:
                        if not self.has_emt:
                            self.has_emt = child.find("%emt") >= 0
                        if not self.has_eval:
                            self.has_eval = child.find("%eval") >= 0

        # Collect all variation paths into a list of board lists
        # where the first one will be the boards of mainline game.
        # model.boards will allways point to the current shown variation
        # which will be model.variations[0] when we are in the mainline.
        walk(model, boards[0], [])
        model.boards = model.variations[0]
        self.has_emt = self.has_emt and model.timed
        if self.has_emt or self.has_eval:
            if self.has_emt:
                blacks = len(model.moves) // 2
                whites = len(model.moves) - blacks

                model.timemodel.intervals = [
                    [model.timemodel.intervals[0][0]] * (whites + 1),
                    [model.timemodel.intervals[1][0]] * (blacks + 1),
                ]
                model.timemodel.intervals[0][0] = secs
                model.timemodel.intervals[1][0] = secs
            for ply, board in enumerate(boards):
                for child in board.children:
                    if isinstance(child, str):
                        if self.has_emt:
                            match = move_time_re.search(child)
                            if match:
                                movecount, color = divmod(ply + 1, 2)
                                hour, minute, sec, msec = match.groups()
                                prev = model.timemodel.intervals[color][
                                    movecount - 1]
                                hour = 0 if hour is None else int(hour[:-1])
                                minute = 0 if minute is None else int(
                                    minute[:-1])
                                msec = 0 if msec is None else int(msec)
                                msec += int(sec) * 1000 + int(
                                    minute) * 60 * 1000 + int(
                                        hour) * 60 * 60 * 1000
                                model.timemodel.intervals[color][
                                    movecount] = prev - msec / 1000. + gain

                        if self.has_eval:
                            match = move_eval_re.search(child)
                            if match:
                                sign, num, fraction, depth = match.groups()
                                sign = 1 if sign is None or sign == "+" else -1
                                num = int(num)
                                fraction = 0 if fraction is None else int(
                                    fraction)
                                value = sign * (num * 100 + fraction)
                                depth = "" if depth is None else depth
                                if board.color == BLACK:
                                    value = -value
                                model.scores[ply] = ("", value, depth)
            log.debug("pgn.loadToModel: intervals %s" %
                      model.timemodel.intervals)

        # Find the physical status of the game
        model.status, model.reason = getStatus(model.boards[-1])

        # Apply result from .pgn if the last position was loaded
        if position == -1 or len(model.moves) == position - model.lowply:
            if self.pgn_is_string:
                result = rec["Result"]
                if result in pgn2Const:
                    status = pgn2Const[result]
                else:
                    status = RUNNING
            else:
                status = rec["Result"]

            if status in (WHITEWON, BLACKWON) and status != model.status:
                model.status = status
                model.reason = WON_RESIGN
            elif status == DRAW and status != model.status:
                model.status = DRAW
                model.reason = DRAW_AGREE

        if model.timed:
            model.timemodel.movingColor = model.boards[-1].color

        # If parsing gave an error we throw it now, to enlarge our possibility
        # of being able to continue the game from where it failed.
        if self.error:
            raise self.error

        return model
Ejemplo n.º 22
0
    def loadToModel(self, gameno, position=-1, model=None):
        if not model:
            model = GameModel()

        # the seven mandatory PGN headers
        model.tags['Event'] = self._getTag(gameno, 'Event')
        model.tags['Site'] = self._getTag(gameno, 'Site')
        model.tags['Date'] = self._getTag(gameno, 'Date')
        model.tags['Round'] = self.get_round(gameno)
        model.tags['White'], model.tags['Black'] = self.get_player_names(
            gameno)
        model.tags['Result'] = reprResult[self.get_result(gameno)]

        if model.tags['Date']:
            date_match = re.match(".*(\d{4}).(\d{2}).(\d{2}).*",
                                  model.tags['Date'])
            if date_match:
                year, month, day = date_match.groups()
                model.tags['Year'] = year
                model.tags['Month'] = month
                model.tags['Day'] = day

                # non-mandatory headers
        for tag in ('Annotator', 'ECO', 'WhiteElo', 'BlackElo', 'TimeControl'):
            if self._getTag(gameno, tag):
                model.tags[tag] = self._getTag(gameno, tag)
            else:
                model.tags[tag] = ""

        model.info = self.get_info(gameno)

        # TODO: enable this when NewGameDialog is altered to give user option of
        # whether to use PGN's clock time, or their own custom time. Also,
        # dialog should set+insensitize variant based on the variant of the
        # game selected in the dialog
        if model.tags['TimeControl']:
            secs, gain = parseTimeControlTag(model.tags['TimeControl'])
            model.timed = True
            model.timemodel.secs = secs
            model.timemodel.gain = gain
            model.timemodel.minutes = secs / 60
            for tag, color in (('WhiteClock', WHITE), ('BlackClock', BLACK)):
                if self._getTag(gameno, tag):
                    try:
                        millisec = parseClockTimeTag(self._getTag(gameno, tag))
                        # We need to fix when FICS reports negative clock time like this
                        # [TimeControl "180+0"]
                        # [WhiteClock "0:00:15.867"]
                        # [BlackClock "23:59:58.820"]
                        start_sec = (
                            millisec - 24 * 60 * 60 * 1000
                        ) / 1000. if millisec > 23 * 60 * 60 * 1000 else millisec / 1000.
                        model.timemodel.intervals[color][0] = start_sec
                    except ValueError:
                        raise LoadingError(
                            "Error parsing '%s' Header for gameno %s" %
                            (tag, gameno))

        fenstr = self._getTag(gameno, "FEN")
        variant = self.get_variant(gameno)

        if variant:
            if variant not in name2variant:
                raise LoadingError("Unknown variant %s for gameno %s" %
                                   (variant, gameno))

            model.tags["Variant"] = variant
            # Fixes for some non statndard Chess960 .pgn
            if (fenstr is not None) and variant == "Fischerandom":
                parts = fenstr.split()
                parts[0] = parts[0].replace(".", "/").replace("0", "")
                if len(parts) == 1:
                    parts.append("w")
                    parts.append("-")
                    parts.append("-")
                fenstr = " ".join(parts)

            model.variant = name2variant[variant]
            board = LBoard(model.variant.variant)
        else:
            model.variant = NormalBoard
            board = LBoard()

        if fenstr:
            try:
                board.applyFen(fenstr)
            except SyntaxError as err:
                board.applyFen(FEN_EMPTY)
                raise LoadingError(
                    _("The game can't be loaded, because of an error parsing FEN"
                      ), err.args[0])
        else:
            board.applyFen(FEN_START)

        boards = [board]

        del model.moves[:]
        del model.variations[:]

        self.error = None
        movetext = self.get_movetext(gameno)

        boards = self.parse_movetext(movetext, boards[0], position)

        # The parser built a tree of lboard objects, now we have to
        # create the high level Board and Move lists...

        for board in boards:
            if board.lastMove is not None:
                model.moves.append(Move(board.lastMove))

        self.has_emt = False
        self.has_eval = False

        def walk(model, node, path):
            if node.prev is None:
                # initial game board
                board = model.variant(setup=node.asFen(), lboard=node)
            else:
                move = Move(node.lastMove)
                try:
                    board = node.prev.pieceBoard.move(move, lboard=node)
                except:
                    raise LoadingError(
                        _("Invalid move."),
                        "%s%s" % (move_count(node, black_periods=True), move))

            if node.next is None:
                model.variations.append(path + [board])
            else:
                walk(model, node.next, path + [board])

            for child in node.children:
                if isinstance(child, list):
                    if len(child) > 1:
                        # non empty variation, go walk
                        walk(model, child[1], list(path))
                else:
                    if not self.has_emt:
                        self.has_emt = child.find("%emt") >= 0
                    if not self.has_eval:
                        self.has_eval = child.find("%eval") >= 0

        # Collect all variation paths into a list of board lists
        # where the first one will be the boards of mainline game.
        # model.boards will allways point to the current shown variation
        # which will be model.variations[0] when we are in the mainline.
        walk(model, boards[0], [])
        model.boards = model.variations[0]
        self.has_emt = self.has_emt and "TimeControl" in model.tags
        if self.has_emt or self.has_eval:
            if self.has_emt:
                blacks = len(model.moves) // 2
                whites = len(model.moves) - blacks

                model.timemodel.intervals = [
                    [model.timemodel.intervals[0][0]] * (whites + 1),
                    [model.timemodel.intervals[1][0]] * (blacks + 1),
                ]
                secs, gain = parseTimeControlTag(model.tags['TimeControl'])
                model.timemodel.intervals[0][0] = secs
                model.timemodel.intervals[1][0] = secs
            for ply, board in enumerate(boards):
                for child in board.children:
                    if isinstance(child, basestring):
                        if self.has_emt:
                            match = movetime.search(child)
                            if match:
                                movecount, color = divmod(ply + 1, 2)
                                hour, minute, sec, msec = match.groups()
                                prev = model.timemodel.intervals[color][
                                    movecount - 1]
                                hour = 0 if hour is None else int(hour[:-1])
                                minute = 0 if minute is None else int(
                                    minute[:-1])
                                msec = 0 if msec is None else int(msec)
                                msec += int(sec) * 1000 + int(
                                    minute) * 60 * 1000 + int(
                                        hour) * 60 * 60 * 1000
                                model.timemodel.intervals[color][
                                    movecount] = prev - msec / 1000. + gain

                        if self.has_eval:
                            match = moveeval.search(child)
                            if match:
                                sign, num, fraction, depth = match.groups()
                                sign = 1 if sign is None or sign == "+" else -1
                                num = int(num) if int(
                                    num) == MATE_VALUE else int(num)
                                fraction = 0 if fraction is None else int(
                                    fraction)
                                value = sign * (num * 100 + fraction)
                                depth = "" if depth is None else depth
                                if board.color == BLACK:
                                    value = -value
                                model.scores[ply] = ("", value, depth)
            log.debug("pgn.loadToModel: intervals %s" %
                      model.timemodel.intervals)
        # Find the physical status of the game
        model.status, model.reason = getStatus(model.boards[-1])

        # Apply result from .pgn if the last position was loaded
        if position == -1 or len(model.moves) == position - model.lowply:
            status = self.get_result(gameno)
            if status in (WHITEWON, BLACKWON) and status != model.status:
                model.status = status
                model.reason = WON_RESIGN
            elif status == DRAW and status != model.status:
                model.status = DRAW
                model.reason = DRAW_AGREE

        # If parsing gave an error we throw it now, to enlarge our possibility
        # of being able to continue the game from where it failed.
        if self.error:
            raise self.error

        return model
Ejemplo n.º 23
0
        if model.timemodel:
            if quick_parse:
                blacks = len(movstrs)/2
                whites = len(movstrs)-blacks
            else:
                blacks = len(model.moves)/2
                whites = len(model.moves)-blacks

            model.timemodel.intervals = [
                [model.timemodel.intervals[0][0]]*(whites+1),
                [model.timemodel.intervals[1][0]]*(blacks+1),
            ]
            log.debug("intervals %s\n" % model.timemodel.intervals)

        if model.status == WAITING_TO_START:
            model.status, model.reason = getStatus(model.boards[-1])
            model.status = self.get_result(gameno)

        if error:
            raise error

        return model

    def _getTag (self, gameno, tagkey):
        if gameno in self.tagcache:
            if tagkey in self.tagcache[gameno]:
                return self.tagcache[gameno][tagkey]
            else: return None
        else:
            if self.games:
                self.tagcache[gameno] = dict(tagre.findall(self.games[gameno][0]))
Ejemplo n.º 24
0
    def loadToModel(self, gameno, position=-1, model=None):
        if not model:
            model = GameModel()

        # the seven mandatory PGN headers
        model.tags['Event'] = self._getTag(gameno, 'Event')
        model.tags['Site'] = self._getTag(gameno, 'Site')
        model.tags['Date'] = self._getTag(gameno, 'Date')
        model.tags['Round'] = self.get_round(gameno)
        model.tags['White'], model.tags['Black'] = self.get_player_names(
            gameno)
        model.tags['Result'] = reprResult[self.get_result(gameno)]

        pgnHasYearMonthDay = True
        for tag in ('Year', 'Month', 'Day'):
            if not self._getTag(gameno, tag):
                pgnHasYearMonthDay = False
                break
        if model.tags['Date'] and not pgnHasYearMonthDay:
            date_match = re.match(".*(\d{4}).(\d{2}).(\d{2}).*",
                                  model.tags['Date'])
            if date_match:
                year, month, day = date_match.groups()
                model.tags['Year'] = year
                model.tags['Month'] = month
                model.tags['Day'] = day

        # non-mandatory headers
        for tag in ('Annotator', 'ECO', 'EventDate', 'Time', 'WhiteElo',
                    'BlackElo', 'TimeControl'):
            if self._getTag(gameno, tag):
                model.tags[tag] = self._getTag(gameno, tag)

        # TODO: enable this when NewGameDialog is altered to give user option of
        # whether to use PGN's clock time, or their own custom time. Also,
        # dialog should set+insensitize variant based on the variant of the
        # game selected in the dialog
#        if model.timed:
#            for tag, color in (('WhiteClock', WHITE), ('BlackClock', BLACK)):
#                if self._getTag(gameno, tag):
#                    try:
#                        ms = parseClockTimeTag(self._getTag(gameno, tag))
#                        model.timemodel.intervals[color][0] = ms / 1000
#                    except ValueError:
#                        raise LoadingError( \
#                            "Error parsing '%s' Header for gameno %s" % (tag, gameno))
#            if model.tags['TimeControl']:
#                minutes, gain = parseTimeControlTag(model.tags['TimeControl'])
#                model.timemodel.minutes = minutes
#                model.timemodel.gain = gain

        fenstr = self._getTag(gameno, "FEN")
        variant = self.get_variant(gameno)

        if variant:
            # Fixes for some non statndard Chess960 .pgn
            if (fenstr is not None) and variant == "Fischerandom":
                model.tags["Variant"] = "Fischerandom"
                parts = fenstr.split()
                parts[0] = parts[0].replace(".", "/").replace("0", "")
                if len(parts) == 1:
                    parts.append("w")
                    parts.append("-")
                    parts.append("-")
                fenstr = " ".join(parts)
            elif variant == "Atomic":
                model.tags["Variant"] = "Atomic"
            elif variant == "Crazyhouse":
                model.tags["Variant"] = "Crazyhouse"
            elif variant == "Wildcastle":
                model.tags["Variant"] = "Wildcastle"
            elif variant == "Suicide":
                model.tags["Variant"] = "Suicide"
            elif variant == "Losers":
                model.tags["Variant"] = "Losers"
            elif variant == "Kingofthehill":
                model.tags["Variant"] = "Kingofthehill"

        if variant == "Fischerandom":
            board = LBoard(FISCHERRANDOMCHESS)
            model.variant = FischerRandomChess
        elif variant == "Atomic":
            board = LBoard(ATOMICCHESS)
            model.variant = AtomicChess
        elif variant == "Crazyhouse":
            board = LBoard(CRAZYHOUSECHESS)
            model.variant = CrazyhouseChess
        elif variant == "Wildcastle":
            board = LBoard(WILDCASTLECHESS)
            model.variant = WildcastleChess
        elif variant == "Suicide":
            board = LBoard(SUICIDECHESS)
            model.variant = SuicideChess
        elif variant == "Losers":
            board = LBoard(LOSERSCHESS)
            model.variant = LosersChess
        elif variant == "Kingofthehill":
            board = LBoard(KINGOFTHEHILLCHESS)
            model.variant = KingOfTheHillChess
        else:
            board = LBoard()

        if fenstr:
            try:
                board.applyFen(fenstr)
            except SyntaxError as e:
                board.applyFen(FEN_EMPTY)
                raise LoadingError(
                    _("The game can't be loaded, because of an error parsing FEN"
                      ), e.args[0])
        else:
            board.applyFen(FEN_START)

        boards = [board]

        del model.moves[:]
        del model.variations[:]

        self.error = None
        movetext = self.get_movetext(gameno)

        boards = self.parse_string(movetext, boards[0], position)

        # The parser built a tree of lboard objects, now we have to
        # create the high level Board and Move lists...

        for board in boards:
            if board.lastMove is not None:
                model.moves.append(Move(board.lastMove))

        self.has_emt = False
        self.has_eval = False

        def walk(node, path):
            if node.prev is None:
                # initial game board
                if variant == "Fischerandom":
                    board = FRCBoard(setup=node.asFen(), lboard=node)
                elif variant == "Atomic":
                    board = AtomicBoard(setup=node.asFen(), lboard=node)
                elif variant == "Crazyhouse":
                    board = CrazyhouseBoard(setup=node.asFen(), lboard=node)
                elif variant == "Wildcastle":
                    board = WildcastleBoard(setup=node.asFen(), lboard=node)
                elif variant == "Suicide":
                    board = SuicideBoard(setup=node.asFen(), lboard=node)
                elif variant == "Losers":
                    board = LosersBoard(setup=node.asFen(), lboard=node)
                elif variant == "Kingofthehill":
                    board = KingOfTheHillBoard(setup=node.asFen(), lboard=node)
                else:
                    board = Board(setup=node.asFen(), lboard=node)
            else:
                move = Move(node.lastMove)
                try:
                    board = node.prev.pieceBoard.move(move, lboard=node)
                except:
                    raise LoadingError(
                        _("Invalid move."),
                        "%s%s" % (move_count(node, black_periods=True), move))

            if node.next is None:
                model.variations.append(path + [board])
            else:
                walk(node.next, path + [board])

            for child in node.children:
                if isinstance(child, list):
                    if len(child) > 1:
                        # non empty variation, go walk
                        walk(child[1], list(path))
                else:
                    if not self.has_emt:
                        self.has_emt = child.find("%emt") >= 0
                    if not self.has_eval:
                        self.has_eval = child.find("%eval") >= 0

        # Collect all variation paths into a list of board lists
        # where the first one will be the boards of mainline game.
        # model.boards will allways point to the current shown variation
        # which will be model.variations[0] when we are in the mainline.
        walk(boards[0], [])
        model.boards = model.variations[0]

        self.has_emt = self.has_emt and "TimeControl" in model.tags
        if self.has_emt or self.has_eval:
            if self.has_emt:
                blacks = len(model.moves) // 2
                whites = len(model.moves) - blacks

                model.timemodel.intervals = [
                    [model.timemodel.intervals[0][0]] * (whites + 1),
                    [model.timemodel.intervals[1][0]] * (blacks + 1),
                ]
                secs, gain = parseTimeControlTag(model.tags['TimeControl'])
                model.timemodel.intervals[0][0] = secs
                model.timemodel.intervals[1][0] = secs

            for ply, board in enumerate(boards):
                for child in board.children:
                    if isinstance(child, basestring):
                        if self.has_emt:
                            match = movetime.search(child)
                            if match:
                                movecount, color = divmod(ply + 1, 2)
                                hour, minute, sec, msec = match.groups()
                                prev = model.timemodel.intervals[color][
                                    movecount - 1]
                                msec = 0 if msec is None else int(msec)
                                msec += int(sec) * 1000 + int(
                                    minute) * 60 * 1000 + int(
                                        hour) * 60 * 60 * 1000
                                model.timemodel.intervals[color][
                                    movecount] = prev - msec / 1000

                        if self.has_eval:
                            match = moveeval.search(child)
                            if match:
                                sign, num, fraction, depth = match.groups()
                                sign = 1 if sign is None or sign == "+" else -1
                                num = int(num) if int(
                                    num) == MATE_VALUE else int(num)
                                fraction = 0 if fraction is None else float(
                                    fraction) / 100
                                value = sign * (num + fraction)
                                depth = "" if depth is None else depth
                                model.scores[ply] = ("", value, depth)

            log.debug("pgn.loadToModel: intervals %s" %
                      model.timemodel.intervals)

        # Find the physical status of the game
        model.status, model.reason = getStatus(model.boards[-1])

        # Apply result from .pgn if the last position was loaded
        if position == -1 or len(model.moves) == position - model.lowply:
            status = self.get_result(gameno)
            if status in (WHITEWON, BLACKWON) and status != model.status:
                model.status = status
                model.reason = WON_RESIGN
            elif status == DRAW and status != model.status:
                model.status = DRAW
                model.reason = DRAW_AGREE

        # If parsing gave an error we throw it now, to enlarge our possibility
        # of being able to continue the game from where it failed.
        if self.error:
            raise self.error

        return model
Ejemplo n.º 25
0
    def test_getstatus3(self):
        """Testing possible to mate with the queen unaided in Atomic variant"""

        board = AtomicBoard(setup=FEN4)
        print(board)
        self.assertEqual(getStatus(board), (WHITEWON, WON_MATE))
Ejemplo n.º 26
0
    def loadToModel (self, gameno, position=-1, model=None):
        if not model:
            model = GameModel()

        # the seven mandatory PGN headers
        model.tags['Event'] = self._getTag(gameno, 'Event')
        model.tags['Site'] = self._getTag(gameno, 'Site')
        model.tags['Date'] = self._getTag(gameno, 'Date')
        model.tags['Round'] = self.get_round(gameno)
        model.tags['White'], model.tags['Black'] = self.get_player_names(gameno)
        model.tags['Result'] = reprResult[self.get_result(gameno)]
        
        pgnHasYearMonthDay = True
        for tag in ('Year', 'Month', 'Day'):
            if not self._getTag(gameno, tag):
                pgnHasYearMonthDay = False
                break
        if model.tags['Date'] and not pgnHasYearMonthDay:
            date_match = re.match(".*(\d{4}).(\d{2}).(\d{2}).*", model.tags['Date'])
            if date_match:
                year, month, day = date_match.groups()
                model.tags['Year'] = year
                model.tags['Month'] = month
                model.tags['Day'] = day
                
        # non-mandatory headers
        for tag in ('Annotator', 'ECO', 'EventDate', 'Time', 'WhiteElo', 'BlackElo', 'TimeControl'):
            if self._getTag(gameno, tag):
                model.tags[tag] = self._getTag(gameno, tag)
            else:
                model.tags[tag] = ""

        # TODO: enable this when NewGameDialog is altered to give user option of
        # whether to use PGN's clock time, or their own custom time. Also,
        # dialog should set+insensitize variant based on the variant of the
        # game selected in the dialog
        if model.tags['TimeControl']:
            secs, gain = parseTimeControlTag(model.tags['TimeControl'])
            model.timed = True
            model.timemodel.secs = secs
            model.timemodel.gain = gain
            model.timemodel.minutes = secs / 60

            for tag, color in (('WhiteClock', WHITE), ('BlackClock', BLACK)):
                if self._getTag(gameno, tag):
                    try:
                        ms = parseClockTimeTag(self._getTag(gameno, tag))
                        model.timemodel.intervals[color][0] = ms / 1000
                    except ValueError: 
                        raise LoadingError( \
                            "Error parsing '%s' Header for gameno %s" % (tag, gameno))
        
        fenstr = self._getTag(gameno, "FEN")
        variant = self.get_variant(gameno)
        
        if variant:
            model.tags["Variant"] = variant
            # Fixes for some non statndard Chess960 .pgn
            if (fenstr is not None) and variant == "Fischerandom":
                parts = fenstr.split()
                parts[0] = parts[0].replace(".", "/").replace("0", "")
                if len(parts) == 1:
                    parts.append("w")
                    parts.append("-")
                    parts.append("-")
                fenstr = " ".join(parts)

            model.variant = name2variant[variant]
            board = LBoard(model.variant.variant)
        else:
            model.variant = NormalBoard
            board = LBoard()

        if fenstr:
            try:
                board.applyFen(fenstr)
            except SyntaxError as e:
                board.applyFen(FEN_EMPTY)
                raise LoadingError(_("The game can't be loaded, because of an error parsing FEN"), e.args[0])
        else:
            board.applyFen(FEN_START)
        
        boards = [board]

        del model.moves[:]
        del model.variations[:]
        
        self.error = None
        movetext = self.get_movetext(gameno)
        
        boards = self.parse_string(movetext, boards[0], position)

        # The parser built a tree of lboard objects, now we have to
        # create the high level Board and Move lists...
        
        for board in boards:
            if board.lastMove is not None:
                model.moves.append(Move(board.lastMove))
        
        self.has_emt = False
        self.has_eval = False
        
        def walk(node, path):
            if node.prev is None:
                # initial game board
                board = model.variant(setup=node.asFen(), lboard=node)
            else:
                move = Move(node.lastMove)
                try:
                    board = node.prev.pieceBoard.move(move, lboard=node)
                except:
                    raise LoadingError(_("Invalid move."), "%s%s" % (move_count(node, black_periods=True), move))

            if node.next is None:
                model.variations.append(path+[board])
            else:
                walk(node.next, path+[board])

            for child in node.children:
                if isinstance(child, list):
                    if len(child) > 1:
                        # non empty variation, go walk
                        walk(child[1], list(path))
                else:
                    if not self.has_emt:
                        self.has_emt = child.find("%emt") >= 0
                    if not self.has_eval:
                        self.has_eval = child.find("%eval") >= 0
        
        # Collect all variation paths into a list of board lists
        # where the first one will be the boards of mainline game.
        # model.boards will allways point to the current shown variation
        # which will be model.variations[0] when we are in the mainline.
        walk(boards[0], [])
        model.boards = model.variations[0]
        
        self.has_emt = self.has_emt and "TimeControl" in model.tags
        if self.has_emt or self.has_eval:
            if self.has_emt:
                blacks = len(model.moves)//2
                whites = len(model.moves)-blacks

                model.timemodel.intervals = [
                    [model.timemodel.intervals[0][0]]*(whites+1),
                    [model.timemodel.intervals[1][0]]*(blacks+1),
                ]
                secs, gain = parseTimeControlTag(model.tags['TimeControl'])
                model.timemodel.intervals[0][0] = secs
                model.timemodel.intervals[1][0] = secs
            
            for ply, board in enumerate(boards):
                for child in board.children:
                    if isinstance(child, basestring):
                        if self.has_emt:
                            match = movetime.search(child)
                            if match:
                                movecount, color = divmod(ply+1, 2)
                                hour, minute, sec, msec = match.groups()
                                prev = model.timemodel.intervals[color][movecount-1]
                                msec = 0 if msec is None else int(msec)
                                msec += int(sec)*1000 + int(minute)*60*1000 + int(hour)*60*60*1000
                                model.timemodel.intervals[color][movecount] = prev - msec/1000
                        
                        if self.has_eval:
                            match = moveeval.search(child)
                            if match:
                                sign, num, fraction, depth = match.groups()
                                sign = 1 if sign is None or sign == "+" else -1
                                num = int(num) if int(num) == MATE_VALUE else int(num)
                                fraction = 0 if fraction is None else float(fraction)/100
                                value = sign * (num + fraction)
                                depth = "" if depth is None else depth
                                model.scores[ply] = ("", value, depth)

            log.debug("pgn.loadToModel: intervals %s" % model.timemodel.intervals)

        # Find the physical status of the game
        model.status, model.reason = getStatus(model.boards[-1])
        
        # Apply result from .pgn if the last position was loaded
        if position == -1 or len(model.moves) == position - model.lowply:
            status = self.get_result(gameno)
            if status in (WHITEWON, BLACKWON) and status != model.status:
                model.status = status
                model.reason = WON_RESIGN
            elif status == DRAW and status != model.status:
                model.status = DRAW
                model.reason = DRAW_AGREE
        
        # If parsing gave an error we throw it now, to enlarge our possibility
        # of being able to continue the game from where it failed.
        if self.error:
            raise self.error

        return model
Ejemplo n.º 27
0
    def loadToModel(self, rec, position=-1, model=None):
        """ Parse game text and load game record header tags to a GameModel object """

        if not model:
            model = GameModel()

        if self.pgn_is_string:
            rec = self.games[0]
            game_date = rec["Date"]
            result = rec["Result"]
            variant = rec["Variant"]
        else:
            game_date = self.get_date(rec)
            result = reprResult[rec["Result"]]
            variant = self.get_variant(rec)

        # the seven mandatory PGN headers
        model.tags['Event'] = rec["Event"]
        model.tags['Site'] = rec["Site"]
        model.tags['Date'] = game_date
        model.tags['Round'] = rec["Round"]
        model.tags['White'] = rec["White"]
        model.tags['Black'] = rec["Black"]
        model.tags['Result'] = result

        if model.tags['Date']:
            date_match = re.match(".*(\d{4}).(\d{2}).(\d{2}).*",
                                  model.tags['Date'])
            if date_match:
                year, month, day = date_match.groups()
                model.tags['Year'] = year
                model.tags['Month'] = month
                model.tags['Day'] = day

        # non-mandatory tags
        for tag in ('Annotator', 'ECO', 'WhiteElo', 'BlackElo', 'TimeControl'):
            value = rec[tag]
            if value:
                model.tags[tag] = value
            else:
                model.tags[tag] = ""

        if not self.pgn_is_string:
            model.info = self.tag_database.get_info(rec)

        if model.tags['TimeControl']:
            secs, gain = parseTimeControlTag(model.tags['TimeControl'])
            model.timed = True
            model.timemodel.secs = secs
            model.timemodel.gain = gain
            model.timemodel.minutes = secs / 60
            for tag, color in (('WhiteClock', WHITE), ('BlackClock', BLACK)):
                if hasattr(rec, tag):
                    try:
                        millisec = parseClockTimeTag(rec[tag])
                        # We need to fix when FICS reports negative clock time like this
                        # [TimeControl "180+0"]
                        # [WhiteClock "0:00:15.867"]
                        # [BlackClock "23:59:58.820"]
                        start_sec = (
                            millisec - 24 * 60 * 60 * 1000
                        ) / 1000. if millisec > 23 * 60 * 60 * 1000 else millisec / 1000.
                        model.timemodel.intervals[color][0] = start_sec
                    except ValueError:
                        raise LoadingError(
                            "Error parsing '%s'" % tag)

        fenstr = rec["FEN"]

        if variant:
            if variant not in name2variant:
                raise LoadingError("Unknown variant %s" % variant)

            model.tags["Variant"] = variant
            # Fixes for some non statndard Chess960 .pgn
            if (fenstr is not None) and variant == "Fischerandom":
                parts = fenstr.split()
                parts[0] = parts[0].replace(".", "/").replace("0", "")
                if len(parts) == 1:
                    parts.append("w")
                    parts.append("-")
                    parts.append("-")
                fenstr = " ".join(parts)

            model.variant = name2variant[variant]
            board = LBoard(model.variant.variant)
        else:
            model.variant = NormalBoard
            board = LBoard()

        if fenstr:
            try:
                board.applyFen(fenstr)
            except SyntaxError as err:
                board.applyFen(FEN_EMPTY)
                raise LoadingError(
                    _("The game can't be loaded, because of an error parsing FEN"),
                    err.args[0])
        else:
            board.applyFen(FEN_START)

        boards = [board]

        del model.moves[:]
        del model.variations[:]

        self.error = None
        movetext = self.get_movetext(rec)

        boards = self.parse_movetext(movetext, boards[0], position)

        # The parser built a tree of lboard objects, now we have to
        # create the high level Board and Move lists...

        for board in boards:
            if board.lastMove is not None:
                model.moves.append(Move(board.lastMove))

        self.has_emt = False
        self.has_eval = False

        def walk(model, node, path):
            if node.prev is None:
                # initial game board
                board = model.variant(setup=node.asFen(), lboard=node)
            else:
                move = Move(node.lastMove)
                try:
                    board = node.prev.pieceBoard.move(move, lboard=node)
                except:
                    raise LoadingError(
                        _("Invalid move."),
                        "%s%s" % (move_count(node, black_periods=True), move))

            if node.next is None:
                model.variations.append(path + [board])
            else:
                walk(model, node.next, path + [board])

            for child in node.children:
                if isinstance(child, list):
                    if len(child) > 1:
                        # non empty variation, go walk
                        walk(model, child[1], list(path))
                else:
                    if not self.has_emt:
                        self.has_emt = child.find("%emt") >= 0
                    if not self.has_eval:
                        self.has_eval = child.find("%eval") >= 0

        # Collect all variation paths into a list of board lists
        # where the first one will be the boards of mainline game.
        # model.boards will allways point to the current shown variation
        # which will be model.variations[0] when we are in the mainline.
        walk(model, boards[0], [])
        model.boards = model.variations[0]
        self.has_emt = self.has_emt and "TimeControl" in model.tags
        if self.has_emt or self.has_eval:
            if self.has_emt:
                blacks = len(model.moves) // 2
                whites = len(model.moves) - blacks

                model.timemodel.intervals = [
                    [model.timemodel.intervals[0][0]] * (whites + 1),
                    [model.timemodel.intervals[1][0]] * (blacks + 1),
                ]
                secs, gain = parseTimeControlTag(model.tags['TimeControl'])
                model.timemodel.intervals[0][0] = secs
                model.timemodel.intervals[1][0] = secs
            for ply, board in enumerate(boards):
                for child in board.children:
                    if isinstance(child, str):
                        if self.has_emt:
                            match = movetime.search(child)
                            if match:
                                movecount, color = divmod(ply + 1, 2)
                                hour, minute, sec, msec = match.groups()
                                prev = model.timemodel.intervals[color][
                                    movecount - 1]
                                hour = 0 if hour is None else int(hour[:-1])
                                minute = 0 if minute is None else int(minute[:-1])
                                msec = 0 if msec is None else int(msec)
                                msec += int(sec) * 1000 + int(
                                    minute) * 60 * 1000 + int(
                                        hour) * 60 * 60 * 1000
                                model.timemodel.intervals[color][
                                    movecount] = prev - msec / 1000. + gain

                        if self.has_eval:
                            match = moveeval.search(child)
                            if match:
                                sign, num, fraction, depth = match.groups()
                                sign = 1 if sign is None or sign == "+" else -1
                                num = int(num) if int(
                                    num) == MATE_VALUE else int(num)
                                fraction = 0 if fraction is None else int(
                                    fraction)
                                value = sign * (num * 100 + fraction)
                                depth = "" if depth is None else depth
                                if board.color == BLACK:
                                    value = -value
                                model.scores[ply] = ("", value, depth)
            log.debug("pgn.loadToModel: intervals %s" %
                      model.timemodel.intervals)

        # Find the physical status of the game
        model.status, model.reason = getStatus(model.boards[-1])

        # Apply result from .pgn if the last position was loaded
        if position == -1 or len(model.moves) == position - model.lowply:
            status = rec["Result"]
            if status in (WHITEWON, BLACKWON) and status != model.status:
                model.status = status
                model.reason = WON_RESIGN
            elif status == DRAW and status != model.status:
                model.status = DRAW
                model.reason = DRAW_AGREE

        # If parsing gave an error we throw it now, to enlarge our possibility
        # of being able to continue the game from where it failed.
        if self.error:
            raise self.error

        return model
Ejemplo n.º 28
0
        if model.timemodel:
            if quick_parse:
                blacks = len(movstrs) / 2
                whites = len(movstrs) - blacks
            else:
                blacks = len(model.moves) / 2
                whites = len(model.moves) - blacks

            model.timemodel.intervals = [
                [model.timemodel.intervals[0][0]] * (whites + 1),
                [model.timemodel.intervals[1][0]] * (blacks + 1),
            ]
            log.debug("intervals %s\n" % model.timemodel.intervals)

        if model.status == WAITING_TO_START:
            model.status, model.reason = getStatus(model.boards[-1])
            model.status = self.get_result(gameno)

        if error:
            raise error

        return model

    def _getTag(self, gameno, tagkey):
        if gameno in self.tagcache:
            if tagkey in self.tagcache[gameno]:
                return self.tagcache[gameno][tagkey]
            else:
                return None
        else:
            if self.games: