Ejemplo n.º 1
0
 def key_pressed (self, keyname):
     if keyname in "PNBRQKMFSOox12345678abcdefgh":
         self.keybuffer += keyname
     elif keyname == "minus":
         self.keybuffer += "-"
     elif keyname == "at":
         self.keybuffer += "@"
     elif keyname == "equal":
         self.keybuffer += "="
     elif keyname == "Return":
         color = self.view.model.boards[-1].color
         board = self.view.model.getBoardAtPly(self.view.shown, self.view.shownVariationIdx)
         try:
             move = parseAny(board, self.keybuffer)
         except:
             self.keybuffer = ""
             return
         if validate(board, move):
             if self.view.shownIsMainLine() and self.view.model.boards[-1] == board:
                 self.emit("piece_moved", move, color)
             else:
                 if board.board.next is None and not self.view.shownIsMainLine():
                     self.view.model.add_move2variation(board, move, self.view.shownVariationIdx)
                     self.view.shown += 1
                 else:
                     new_vari = self.view.model.add_variation(board, (move,))
                     self.view.setShownBoard(new_vari[-1])
         self.keybuffer = ""
     elif keyname == "BackSpace":
         self.keybuffer = self.keybuffer[:-1] if self.keybuffer else ""
Ejemplo n.º 2
0
    def key_pressed(self, keyname):
        if keyname in "PNBRQKMFSOox12345678abcdefgh":
            self.keybuffer += keyname

        elif keyname == "minus":
            self.keybuffer += "-"

        elif keyname == "at":
            self.keybuffer += "@"

        elif keyname == "equal":
            self.keybuffer += "="

        elif keyname == "Return":
            color = self.view.model.boards[-1].color
            board = self.view.model.getBoardAtPly(
                self.view.shown, self.view.shown_variation_idx)
            try:
                move = parseAny(board, self.keybuffer)
            except ParsingError:
                self.keybuffer = ""
                return

            if validate(board, move):
                if ((self.view.model.curplayer.__type__ == LOCAL
                     or self.view.model.examined)
                        and self.view.shownIsMainLine()
                        and self.view.model.boards[-1] == board
                        and self.view.model.status == RUNNING):
                    # emit move
                    self.emit("piece_moved", move, color)
                    if self.view.model.examined:
                        self.view.model.connection.bm.sendMove(
                            toAN(board, move))
                else:
                    self.play_or_add_move(board, move)
            self.keybuffer = ""

        elif keyname == "BackSpace":
            self.keybuffer = self.keybuffer[:-1] if self.keybuffer else ""
Ejemplo n.º 3
0
    def key_pressed(self, keyname):
        if keyname in "PNBRQKMFSOox12345678abcdefgh":
            self.keybuffer += keyname

        elif keyname == "minus":
            self.keybuffer += "-"

        elif keyname == "at":
            self.keybuffer += "@"

        elif keyname == "equal":
            self.keybuffer += "="

        elif keyname == "Return":
            color = self.view.model.boards[-1].color
            board = self.view.model.getBoardAtPly(
                self.view.shown, self.view.shown_variation_idx)
            try:
                move = parseAny(board, self.keybuffer)
            except:
                self.keybuffer = ""
                return

            if validate(board, move):
                if (self.view.model.curplayer.__type__ == LOCAL or self.view.model.examined) and \
                        self.view.shownIsMainLine() and \
                        self.view.model.boards[-1] == board and \
                        self.view.model.status == RUNNING:
                    # emit move
                    self.emit("piece_moved", move, color)
                    if self.view.model.examined:
                        self.view.model.connection.bm.sendMove(toAN(board, move))
                else:
                    play_or_add_move(self.view, board, move)
            self.keybuffer = ""

        elif keyname == "BackSpace":
            self.keybuffer = self.keybuffer[:-1] if self.keybuffer else ""
Ejemplo n.º 4
0
    def coro(gamemodel, steps):
        exit_lecture = False
        inside_bsetup = False
        paused = False
        moves_played = 0

        KIBITZ, BACKWARD, BSETUP, BSETUP_DONE, FEN, TOMOVE, WCASTLE, BCASTLE, \
            WNAME, BNAME, REVERT, WAIT, MOVE = range(13)

        while True:
            try:
                step = next(steps)
                print(step)

                parts = step.strip().split()

                command = None
                param = ""

                if parts[0] == "k" or parts[0] == "kibitz":
                    command = KIBITZ
                    param = " ".join(parts[1:])
                elif parts[0] == "back":
                    command = BACKWARD
                    param = int(parts[1]) if len(parts) > 1 else 1
                elif parts[0] == "bsetup":
                    if len(parts) == 1:
                        command = BSETUP
                    else:
                        if parts[1] == "done":
                            command = BSETUP_DONE
                        elif parts[1] == "fen":
                            command = FEN
                            param = parts[2]
                        elif parts[1] == "tomove":
                            command = TOMOVE
                            param = "w" if parts[2].lower()[0] == "w" else "b"
                        elif parts[1] == "wcastle":
                            command = WCASTLE
                            param = parts[2]
                        elif parts[1] == "bcastle":
                            command = BCASTLE
                            param = parts[2]
                elif parts[0] == "tomove":
                    command = TOMOVE
                    param = "w" if parts[1].lower()[0] == "w" else "b"
                elif parts[0] == "wname":
                    command = WNAME
                    param = parts[1]
                elif parts[0] == "bname":
                    command = BNAME
                    param = parts[1]
                elif parts[0] == "revert":
                    command = REVERT
                elif len(parts) == 1 and parts[0].isdigit():
                    command = WAIT
                    param = int(parts[0])
                else:
                    command = MOVE
                    param = parts[0]

                if not inside_bsetup and command == BSETUP:
                    inside_bsetup = True
                    pieces = ""
                    color = ""
                    castl = ""
                    ep = ""
                elif inside_bsetup and command == BSETUP_DONE:
                    inside_bsetup = False

                wait_sec = int(param) if command == WAIT else 2

                if inside_bsetup:
                    wait_sec = -1

                while wait_sec >= 0:
                    if gamemodel.lecture_exit_event.is_set():
                        gamemodel.lecture_exit_event.clear()
                        exit_lecture = True
                        break

                    if gamemodel.lecture_skip_event.is_set():
                        gamemodel.lecture_skip_event.clear()
                        paused = False
                        break

                    if gamemodel.lecture_pause_event.is_set():
                        gamemodel.lecture_pause_event.clear()
                        paused = True

                    yield from asyncio.sleep(0.1)
                    if not paused:
                        wait_sec = wait_sec - 0.1

                if exit_lecture:
                    gamemodel.players[0].putMessage("Lecture exited.")
                    break

                if command != WAIT:
                    if command == KIBITZ:
                        gamemodel.players[0].putMessage(param)
                    if command == BACKWARD:
                        gamemodel.undoMoves(param)
                        moves_played -= param
                    if command == MOVE:
                        board = gamemodel.getBoardAtPly(gamemodel.ply)
                        move = parseAny(board, param)
                        gamemodel.curplayer.move_queue.put_nowait(move)
                        moves_played += 1
                    elif command == REVERT:
                        gamemodel.undoMoves(moves_played)
                        moves_played = 0
                    elif command == BNAME:
                        gamemodel.players[BLACK].name = param
                        gamemodel.emit("players_changed")
                    elif command == WNAME:
                        gamemodel.players[WHITE].name = param
                        gamemodel.emit("players_changed")
                    elif command == FEN:
                        pieces = param
                    elif command == TOMOVE:
                        color = param
                    elif command == WCASTLE:
                        if param == "both":
                            castl += "KQ"
                        elif param == "kside":
                            castl += "K"
                        elif param == "qside":
                            castl += "Q"
                    elif command == BCASTLE:
                        if param == "both":
                            castl += "kq"
                        elif param == "kside":
                            castl += "k"
                        elif param == "qside":
                            castl += "q"
                    elif command == BSETUP_DONE:
                        if not castl:
                            castl = "-"
                        if not ep:
                            ep = "-"
                        fen = "%s %s %s %s 0 1" % (pieces, color, castl, ep)

                        curplayer = gamemodel.curplayer
                        gamemodel.status = RUNNING
                        gamemodel.loadAndStart(StringIO(fen),
                                               fen_loader,
                                               0,
                                               -1,
                                               first_time=False)
                        curplayer.move_queue.put_nowait("int")
                        gamemodel.emit("game_started")
                        moves_played = 0

            except StopIteration:
                # connection.client.run_command("kibitz That concludes this lecture.")
                break
Ejemplo n.º 5
0
    def parseLine(self, proc):
        while True:
            line = yield from wait_signal(proc, 'line')
            if not line:
                break
            else:
                line = line[1]
                if line[0:1] == "#":
                    # Debug line which we shall ignore as specified in CECPv2 specs
                    continue

        #        log.debug("__parseLine: line=\"%s\"" % line.strip(), extra={"task":self.defname})
                parts = whitespaces.split(line.strip())
                if parts[0] == "pong":
                    self.lastpong = int(parts[1])
                    continue

                # Illegal Move
                if parts[0].lower().find("illegal") >= 0:
                    log.warning("__parseLine: illegal move: line=\"%s\", board=%s" % (
                        line.strip(), self.board), extra={"task": self.defname})
                    if parts[-2] == "sd" and parts[-1].isdigit():
                        print("depth", parts[-1], file=self.engine)
                    continue

                # A Move (Perhaps)
                if self.board:
                    if parts[0] == "move":
                        movestr = parts[1]
                    # Old Variation
                    elif d_plus_dot_expr.match(parts[0]) and parts[1] == "...":
                        movestr = parts[2]
                    else:
                        movestr = False

                    if movestr:
                        self.waitingForMove = False
                        self.readyForMoveNowCommand = False
                        if self.engineIsInNotPlaying:
                            # If engine was set in pause just before the engine sent its
                            # move, we ignore it. However the engine has to know that we
                            # ignored it, and thus we step it one back
                            log.info("__parseLine: Discarding engine's move: %s" %
                                     movestr,
                                     extra={"task": self.defname})
                            print("undo", file=self.engine)
                            continue
                        else:
                            try:
                                move = parseAny(self.board, movestr)
                            except ParsingError:
                                self.invalid_move = movestr
                                log.info(
                                    "__parseLine: ParsingError engine move: %s %s"
                                    % (movestr, self.board),
                                    extra={"task": self.defname})
                                self.end(WHITEWON if self.board.color == BLACK else
                                         BLACKWON, WON_ADJUDICATION)
                                continue

                            if validate(self.board, move):
                                self.board = None
                                self.queue.put_nowait(move)
                                continue
                            else:
                                self.invalid_move = movestr
                                log.info(
                                    "__parseLine: can't validate engine move: %s %s"
                                    % (movestr, self.board),
                                    extra={"task": self.defname})
                                self.end(WHITEWON if self.board.color == BLACK else
                                         BLACKWON, WON_ADJUDICATION)
                                continue

                # Analyzing
                if self.engineIsInNotPlaying:
                    if parts[:4] == ["0", "0", "0", "0"]:
                        # Crafty doesn't analyze until it is out of book
                        print("book off", file=self.engine)
                        continue

                    match = anare.match(line)
                    if match:
                        depth, score, moves = match.groups()

                        if "mat" in score.lower() or "#" in moves:
                            # Will look either like -Mat 3 or Mat3
                            scoreval = MATE_VALUE
                            if score.startswith('-'):
                                scoreval = -scoreval
                        else:
                            scoreval = int(score)

                        mvstrs = movere.findall(moves)
                        if mvstrs:
                            self.emit("analyze", [(mvstrs, scoreval, depth.strip())])

                        continue

                # Offers draw
                if parts[0:2] == ["offer", "draw"]:
                    self.emit("accept", Offer(DRAW_OFFER))
                    continue

                # Resigns
                if parts[0] == "resign" or \
                        (parts[0] == "tellics" and parts[1] == "resign"):  # buggy crafty

                    # Previously: if "resign" in parts,
                    # however, this is too generic, since "hint", "bk",
                    # "feature option=.." and possibly other, future CECPv2
                    # commands can validly contain the word "resign" without this
                    # being an intentional resign offer.

                    self.emit("offer", Offer(RESIGNATION))
                    continue

                # if parts[0].lower() == "error":
                #    continue

                # Tell User Error
                if parts[0] == "tellusererror":
                    # We don't want to see our stop analyzer hack as an error message
                    if "8/8/8/8/8/8/8/8" in "".join(parts[1:]):
                        continue
                    # Create a non-modal non-blocking message dialog with the error:
                    dlg = Gtk.MessageDialog(parent=None,
                                            flags=0,
                                            type=Gtk.MessageType.WARNING,
                                            buttons=Gtk.ButtonsType.CLOSE,
                                            message_format=None)

                    # Use the engine name if already known, otherwise the defname:
                    displayname = self.name
                    if not displayname:
                        displayname = self.defname

                    # Compose the dialog text:
                    dlg.set_markup(GObject.markup_escape_text(_(
                        "The engine %s reports an error:") % displayname) + "\n\n" +
                        GObject.markup_escape_text(" ".join(parts[1:])))

                    # handle response signal so the "Close" button works:
                    dlg.connect("response", lambda dlg, x: dlg.destroy())

                    dlg.show_all()
                    continue

                # Tell Somebody
                if parts[0][:4] == "tell" and \
                        parts[0][4:] in ("others", "all", "ics", "icsnoalias"):

                    log.info("Ignoring tell %s: %s" %
                             (parts[0][4:], " ".join(parts[1:])))
                    continue

                if "feature" in parts:
                    # Some engines send features after done=1, so we will iterate after done=1 too
                    done1 = False
                    # We skip parts before 'feature', as some engines give us lines like
                    # White (1) : feature setboard=1 analyze...e="GNU Chess 5.07" done=1
                    parts = parts[parts.index("feature"):]
                    for i, pair in enumerate(parts[1:]):

                        # As "parts" is split with no thoughs on quotes or double quotes
                        # we need to do some extra handling.

                        if pair.find("=") < 0:
                            continue
                        key, value = pair.split("=", 1)

                        if key not in self.features:
                            continue

                        if value.startswith('"') and value.endswith('"'):
                            value = value[1:-1]

                        # If our pair was unfinished, like myname="GNU, we search the
                        # rest of the pairs for a quotating mark.
                        elif value[0] == '"':
                            rest = value[1:] + " " + " ".join(parts[2 + i:])
                            j = rest.find('"')
                            if j == -1:
                                log.warning("Missing endquotation in %s feature",
                                            extra={"task": self.defname})
                                value = rest
                            else:
                                value = rest[:j]

                        elif value.isdigit():
                            value = int(value)

                        if key in self.supported_features:
                            print("accepted %s" % key, file=self.engine)
                        else:
                            print("rejected %s" % key, file=self.engine)

                        if key == "done":
                            if value == 1:
                                done1 = True
                                continue
                            elif value == 0:
                                log.info("Adds %d seconds timeout" % TIME_OUT_SECOND,
                                         extra={"task": self.defname})
                                # This'll buy you some more time
                                self.queue.put_nowait("not ready")
                                break

                        if key == "smp" and value == 1:
                            self.options["cores"] = {"name": "cores",
                                                     "type": "spin",
                                                     "default": 1,
                                                     "min": 1,
                                                     "max": 64}
                        elif key == "memory" and value == 1:
                            self.options["memory"] = {"name": "memory",
                                                      "type": "spin",
                                                      "default": 32,
                                                      "min": 1,
                                                      "max": 4096}
                        elif key == "option" and key != "done":
                            option = self.__parse_option(value)
                            self.options[option["name"]] = option
                        else:
                            self.features[key] = value

                        if key == "myname" and not self.name:
                            self.setName(value)

                    if done1:
                        # Start a new game before using the engine:
                        # (CECPv2 engines)
                        print("new", file=self.engine)

                        # We are now ready for play:
                        self.emit("readyForOptions")
                        self.emit("readyForMoves")
                        self.queue.put_nowait("ready")

                # A hack to get better names in protover 1.
                # Unfortunately it wont work for now, as we don't read any lines from
                # protover 1 engines. When should we stop?
                if self.protover == 1:
                    if self.defname[0] in ''.join(parts):
                        basis = self.defname[0]
                        name = ' '.join(itertools.dropwhile(
                            lambda part: basis not in part, parts))
                        self.features['myname'] = name
                        if not self.name:
                            self.setName(name)
Ejemplo n.º 6
0
    def parseLine(self, proc):
        while True:
            line = yield from wait_signal(proc, 'line')
            if not line:
                break
            else:
                line = line[1]
                parts = line.split()
                if not parts:
                    continue
                # Initializing
                if parts[0] == "id":
                    if parts[1] == "name":
                        self.ids[parts[1]] = " ".join(parts[2:])
                        self.setName(self.ids["name"])
                    continue

                if parts[0] == "uciok":
                    self.emit("readyForOptions")
                    continue

                if parts[0] == "readyok":
                    self.emit("readyForMoves")
                    continue

                # Options parsing
                if parts[0] == "option":
                    dic = {}
                    last = 1
                    varlist = []
                    for i in range(2, len(parts) + 1):
                        if i == len(parts) or parts[i] in OPTKEYS:
                            key = parts[last]
                            value = " ".join(parts[last + 1:i])
                            if "type" in dic and dic["type"] in TYPEDIC:
                                value = TYPEDIC[dic["type"]](value)

                            if key == "var":
                                varlist.append(value)
                            elif key == "type" and value == "string":
                                dic[key] = "text"
                            else:
                                dic[key] = value

                            last = i
                    if varlist:
                        dic["choices"] = varlist

                    if "name" in dic:
                        self.options[dic["name"]] = dic
                    continue

                # A Move
                if self.mode == NORMAL and parts[0] == "bestmove":
                    self.needBestmove = False
                    self.bestmove_event.set()
                    self.__sendQueuedGo()

                    if self.ignoreNext:
                        log.debug(
                            "__parseLine: line='%s' self.ignoreNext==True, returning"
                            % line.strip(),
                            extra={"task": self.defname})
                        self.ignoreNext = False
                        self.readyForStop = True
                        continue

                    movestr = parts[1]
                    if not self.waitingForMove:
                        log.warning(
                            "__parseLine: self.waitingForMove==False, ignoring move=%s"
                            % movestr,
                            extra={"task": self.defname})
                        self.pondermove = None
                        continue
                    self.waitingForMove = False

                    try:
                        move = parseAny(self.board, movestr)
                    except ParsingError:
                        self.invalid_move = movestr
                        log.info(
                            "__parseLine: ParsingError engine move: %s %s" %
                            (movestr, self.board),
                            extra={"task": self.defname})
                        self.end(
                            WHITEWON if self.board.color == BLACK else
                            BLACKWON, WON_ADJUDICATION)
                        continue

                    if not validate(self.board, move):
                        # This is critical. To avoid game stalls, we need to resign on
                        # behalf of the engine.
                        log.error(
                            "__parseLine: move=%s didn't validate, putting 'del' \
                                  in returnQueue. self.board=%s" %
                            (repr(move), self.board),
                            extra={"task": self.defname})
                        self.invalid_move = movestr
                        self.end(
                            WHITEWON if self.board.color == BLACK else
                            BLACKWON, WON_ADJUDICATION)
                        continue

                    self._recordMove(self.board.move(move), move, self.board)
                    log.debug("__parseLine: applied move=%s to self.board=%s" %
                              (move, self.board),
                              extra={"task": self.defname})

                    if self.ponderOn:
                        self.pondermove = None
                        # An engine may send an empty ponder line, simply to clear.
                        if len(parts) == 4:
                            # Engines don't always check for everything in their
                            # ponders. Hence we need to validate.
                            # But in some cases, what they send may not even be
                            # correct AN - specially in the case of promotion.
                            try:
                                pondermove = parseAny(self.board, parts[3])
                            except ParsingError:
                                pass
                            else:
                                if validate(self.board, pondermove):
                                    self.pondermove = pondermove
                                    self._startPonder()

                    self.queue.put_nowait(move)
                    log.debug("__parseLine: put move=%s into self.queue=%s" %
                              (move, self.queue),
                              extra={"task": self.defname})
                    continue

                # An Analysis
                if self.mode != NORMAL and parts[0] == "info" and "pv" in parts:
                    multipv = 1
                    if "multipv" in parts:
                        multipv = int(parts[parts.index("multipv") + 1])
                    scoretype = parts[parts.index("score") + 1]
                    if scoretype in ('lowerbound', 'upperbound'):
                        score = None
                    else:
                        score = int(parts[parts.index("score") + 2])
                        if scoretype == 'mate':
                            #                    print >> self.engine, "stop"
                            if score != 0:
                                sign = score / abs(score)
                                score = sign * (MATE_VALUE - abs(score))

                    movstrs = parts[parts.index("pv") + 1:]

                    if "depth" in parts:
                        depth = parts[parts.index("depth") + 1]
                    else:
                        depth = ""

                    if "nps" in parts:
                        nps = parts[parts.index("nps") + 1]
                    else:
                        nps = ""

                    if multipv <= len(self.analysis):
                        self.analysis[multipv - 1] = (self.board.ply, movstrs,
                                                      score, depth, nps)
                    self.emit("analyze", self.analysis)
                    continue

                # An Analyzer bestmove
                if self.mode != NORMAL and parts[0] == "bestmove":
                    log.debug(
                        "__parseLine: processing analyzer bestmove='%s'" %
                        line.strip(),
                        extra={"task": self.defname})
                    self.needBestmove = False
                    self.bestmove_event.set()
                    if parts[1] == "(none)":
                        self.emit("analyze", [])
                    else:
                        self.__sendQueuedGo(sendlast=True)
                    continue

                # Stockfish complaining it received a 'stop' without a corresponding 'position..go'
                if line.strip() == "Unknown command: stop":
                    log.debug("__parseLine: processing '%s'" % line.strip(),
                              extra={"task": self.defname})
                    self.ignoreNext = False
                    self.needBestmove = False
                    self.readyForStop = False
                    self.__sendQueuedGo()
                    continue
Ejemplo n.º 7
0
    def parseLine(self, engine, line):
        if line[0:1] == "#":
            # Debug line which we shall ignore as specified in CECPv2 specs
            return

#        log.debug("__parseLine: line=\"%s\"" % line.strip(), extra={"task":self.defname})
        parts = whitespaces.split(line.strip())

        if parts[0] == "pong":
            self.lastpong = int(parts[1])
            return

        # Illegal Move
        if parts[0].lower().find("illegal") >= 0:
            log.warning("__parseLine: illegal move: line=\"%s\", board=%s" \
                % (line.strip(), self.board), extra={"task":self.defname})
            if parts[-2] == "sd" and parts[-1].isdigit():
                print("depth", parts[-1], file=self.engine)
            return

        # A Move (Perhaps)
        if self.board:
            if parts[0] == "move":
                movestr = parts[1]
            # Old Variation
            elif d_plus_dot_expr.match(parts[0]) and parts[1] == "...":
                movestr = parts[2]
            else:
                movestr = False

            if movestr:
                log.debug("__parseLine: acquiring self.boardLock",
                          extra={"task": self.defname})
                self.waitingForMove = False
                self.readyForMoveNowCommand = False
                self.boardLock.acquire()
                try:
                    if self.engineIsInNotPlaying:
                        # If engine was set in pause just before the engine sent its
                        # move, we ignore it. However the engine has to know that we
                        # ignored it, and thus we step it one back
                        log.info("__parseLine: Discarding engine's move: %s" %
                                 movestr,
                                 extra={"task": self.defname})
                        print("undo", file=self.engine)
                        return
                    else:
                        try:
                            move = parseAny(self.board, movestr)
                        except ParsingError as e:
                            self.invalid_move = movestr
                            log.info(
                                "__parseLine: ParsingError engine move: %s %s"
                                % (movestr, self.board),
                                extra={"task": self.defname})
                            self.end(
                                WHITEWON if self.board.color == BLACK else
                                BLACKWON, WON_ADJUDICATION)
                            return

                        if validate(self.board, move):
                            self.board = None
                            self.returnQueue.put(move)
                            return
                        else:
                            self.invalid_move = movestr
                            log.info(
                                "__parseLine: can't validate engine move: %s %s"
                                % (movestr, self.board),
                                extra={"task": self.defname})
                            self.end(
                                WHITEWON if self.board.color == BLACK else
                                BLACKWON, WON_ADJUDICATION)
                            return
                finally:
                    log.debug("__parseLine(): releasing self.boardLock",
                              extra={"task": self.defname})
                    self.boardLock.release()
                    self.movecon.acquire()
                    self.movecon.notifyAll()
                    self.movecon.release()

        # Analyzing
        if self.engineIsInNotPlaying:
            if parts[:4] == ["0", "0", "0", "0"]:
                # Crafty doesn't analyze until it is out of book
                print("book off", file=self.engine)
                return

            match = anare.match(line)
            if match:
                depth, score, moves = match.groups()

                if "mat" in score.lower() or "#" in moves:
                    # Will look either like -Mat 3 or Mat3
                    scoreval = MATE_VALUE
                    if score.startswith('-'):
                        scoreval = -scoreval
                else:
                    scoreval = int(score)

                mvstrs = movere.findall(moves)
                if mvstrs:
                    self.emit("analyze", [(mvstrs, scoreval, depth.strip())])

                return

        # Offers draw
        if parts[0:2] == ["offer", "draw"]:
            self.emit("accept", Offer(DRAW_OFFER))
            return

        # Resigns
        if parts[0] == "resign" or \
            (parts[0] == "tellics" and parts[1] == "resign"): # buggy crafty

            # Previously: if "resign" in parts,
            # however, this is too generic, since "hint", "bk",
            # "feature option=.." and possibly other, future CECPv2
            # commands can validly contain the word "resign" without this
            # being an intentional resign offer.

            self.emit("offer", Offer(RESIGNATION))
            return

        #if parts[0].lower() == "error":
        #    return

        #Tell User Error
        if parts[0] == "tellusererror":
            # We don't want to see our stop analyzer hack as an error message
            if "8/8/8/8/8/8/8/8" in "".join(parts[1:]):
                return
            # Create a non-modal non-blocking message dialog with the error:
            dlg = Gtk.MessageDialog(parent=None,
                                    flags=0,
                                    type=Gtk.MessageType.WARNING,
                                    buttons=Gtk.ButtonsType.CLOSE,
                                    message_format=None)

            # Use the engine name if already known, otherwise the defname:
            displayname = self.name
            if not displayname:
                displayname = self.defname

            # Compose the dialog text:
            dlg.set_markup(
                GObject.markup_escape_text(
                    _("The engine %s reports an error:") % displayname) +
                "\n\n" + GObject.markup_escape_text(" ".join(parts[1:])))

            # handle response signal so the "Close" button works:
            dlg.connect("response", lambda dlg, x: dlg.destroy())

            dlg.show_all()
            return

        # Tell Somebody
        if parts[0][:4] == "tell" and \
                parts[0][4:] in ("others", "all", "ics", "icsnoalias"):

            log.info("Ignoring tell %s: %s" %
                     (parts[0][4:], " ".join(parts[1:])))
            return

        if "feature" in parts:
            # Some engines send features after done=1, so we will iterate after done=1 too
            done1 = False
            # We skip parts before 'feature', as some engines give us lines like
            # White (1) : feature setboard=1 analyze...e="GNU Chess 5.07" done=1
            parts = parts[parts.index("feature"):]
            for i, pair in enumerate(parts[1:]):

                # As "parts" is split with no thoughs on quotes or double quotes
                # we need to do some extra handling.

                if pair.find("=") < 0:
                    continue
                key, value = pair.split("=", 1)

                if not key in self.features:
                    continue

                if value.startswith('"') and value.endswith('"'):
                    value = value[1:-1]

                # If our pair was unfinished, like myname="GNU, we search the
                # rest of the pairs for a quotating mark.
                elif value[0] == '"':
                    rest = value[1:] + " " + " ".join(parts[2 + i:])
                    j = rest.find('"')
                    if j == -1:
                        log.warning("Missing endquotation in %s feature",
                                    extra={"task": self.defname})
                        value = rest
                    else:
                        value = rest[:j]

                elif value.isdigit():
                    value = int(value)

                if key in self.supported_features:
                    print("accepted %s" % key, file=self.engine)
                else:
                    print("rejected %s" % key, file=self.engine)

                if key == "done":
                    if value == 1:
                        done1 = True
                        continue
                    elif value == 0:
                        log.info("Adds %d seconds timeout" % TIME_OUT_SECOND,
                                 extra={"task": self.defname})
                        # This'll buy you some more time
                        self.timeout = time.time() + TIME_OUT_SECOND
                        self.returnQueue.put("not ready")
                        return

                if key == "smp" and value == 1:
                    self.options["cores"] = {
                        "name": "cores",
                        "type": "spin",
                        "default": 1,
                        "min": 1,
                        "max": 64
                    }
                elif key == "memory" and value == 1:
                    self.options["memory"] = {
                        "name": "memory",
                        "type": "spin",
                        "default": 32,
                        "min": 1,
                        "max": 4096
                    }
                elif key == "option" and key != "done":
                    option = self.__parse_option(value)
                    self.options[option["name"]] = option
                else:
                    self.features[key] = value

                if key == "myname" and not self.name:
                    self.setName(value)

            if done1:
                # Start a new game before using the engine:
                # (CECPv2 engines)
                print("new", file=self.engine)

                # We are now ready for play:
                self.emit("readyForOptions")
                self.emit("readyForMoves")
                self.returnQueue.put("ready")

        # A hack to get better names in protover 1.
        # Unfortunately it wont work for now, as we don't read any lines from
        # protover 1 engines. When should we stop?
        if self.protover == 1:
            if self.defname[0] in ''.join(parts):
                basis = self.defname[0]
                name = ' '.join(
                    itertools.dropwhile(lambda part: basis not in part, parts))
                self.features['myname'] = name
                if not self.name:
                    self.setName(name)
Ejemplo n.º 8
0
                def analyse_moves():
                    should_black = conf.get("shouldBlack")
                    should_white = conf.get("shouldWhite")
                    from_current = conf.get("fromCurrent")
                    start_ply = gmwidg.board.view.shown if from_current else 0
                    move_time = int(conf.get("max_analysis_spin"))
                    threshold = int(conf.get("variation_threshold_spin"))
                    for board in gamemodel.boards[start_ply:]:
                        if self.stop_event.is_set():
                            break

                        gmwidg.board.view.setShownBoard(board)
                        self.analyzer.setBoard(board)
                        if self.threat_PV:
                            inv_analyzer.setBoard(board)
                        yield from asyncio.sleep(move_time + 0.1)

                        ply = board.ply - gamemodel.lowply
                        color = (ply - 1) % 2
                        if ply - 1 in gamemodel.scores and ply in gamemodel.scores and (
                            (color == BLACK and should_black) or
                            (color == WHITE and should_white)):
                            oldmoves, oldscore, olddepth = gamemodel.scores[ply
                                                                            -
                                                                            1]
                            oldscore = oldscore * -1 if color == BLACK else oldscore
                            score_str = prettyPrintScore(oldscore, olddepth)
                            moves, score, depth = gamemodel.scores[ply]
                            score = score * -1 if color == WHITE else score
                            diff = score - oldscore
                            if ((diff > threshold and color == BLACK) or
                                (diff < -1 * threshold and color == WHITE)
                                ) and (gamemodel.moves[ply - 1] != parseAny(
                                    gamemodel.boards[ply - 1], oldmoves[0])):
                                if self.threat_PV:
                                    try:
                                        if ply - 1 in gamemodel.spy_scores:
                                            oldmoves0, oldscore0, olddepth0 = gamemodel.spy_scores[
                                                ply - 1]
                                            score_str0 = prettyPrintScore(
                                                oldscore0, olddepth0)
                                            pv0 = listToMoves(
                                                gamemodel.boards[ply - 1],
                                                ["--"] + oldmoves0,
                                                validate=True)
                                            if len(pv0) > 2:
                                                gamemodel.add_variation(
                                                    gamemodel.boards[ply - 1],
                                                    pv0,
                                                    comment="Threatening",
                                                    score=score_str0,
                                                    emit=False)
                                    except ParsingError as e:
                                        # ParsingErrors may happen when parsing "old" lines from
                                        # analyzing engines, which haven't yet noticed their new tasks
                                        log.debug(
                                            "__parseLine: Ignored (%s) from analyzer: ParsingError%s"
                                            % (' '.join(oldmoves), e))
                                try:
                                    pv = listToMoves(gamemodel.boards[ply - 1],
                                                     oldmoves,
                                                     validate=True)
                                    gamemodel.add_variation(
                                        gamemodel.boards[ply - 1],
                                        pv,
                                        comment="Better is",
                                        score=score_str,
                                        emit=False)
                                except ParsingError as e:
                                    # ParsingErrors may happen when parsing "old" lines from
                                    # analyzing engines, which haven't yet noticed their new tasks
                                    log.debug(
                                        "__parseLine: Ignored (%s) from analyzer: ParsingError%s"
                                        % (' '.join(oldmoves), e))

                    self.widgets["analyze_game"].hide()
                    self.widgets["analyze_ok_button"].set_sensitive(True)
                    conf.set("analyzer_check", old_check_value)
                    if self.threat_PV:
                        conf.set("inv_analyzer_check", old_inv_check_value)
                    message.dismiss()

                    gamemodel.emit("analysis_finished")
Ejemplo n.º 9
0
    def parseLine(self, proc):
        while True:
            line = yield from wait_signal(proc, 'line')
            if not line:
                break
            else:
                line = line[1]
                parts = line.split()
                if not parts:
                    continue
                # Initializing
                if parts[0] == "id":
                    if parts[1] == "name":
                        self.ids[parts[1]] = " ".join(parts[2:])
                        self.setName(self.ids["name"])
                    continue

                if parts[0] == "uciok":
                    self.emit("readyForOptions")
                    continue

                if parts[0] == "readyok":
                    self.emit("readyForMoves")
                    continue

                # Options parsing
                if parts[0] == "option":
                    dic = {}
                    last = 1
                    varlist = []
                    for i in range(2, len(parts) + 1):
                        if i == len(parts) or parts[i] in OPTKEYS:
                            key = parts[last]
                            value = " ".join(parts[last + 1:i])
                            if "type" in dic and dic["type"] in TYPEDIC:
                                value = TYPEDIC[dic["type"]](value)

                            if key == "var":
                                varlist.append(value)
                            elif key == "type" and value == "string":
                                dic[key] = "text"
                            else:
                                dic[key] = value

                            last = i
                    if varlist:
                        dic["choices"] = varlist

                    if "name" in dic:
                        self.options[dic["name"]] = dic
                    continue

                # A Move
                if self.mode == NORMAL and parts[0] == "bestmove":
                    self.needBestmove = False
                    self.__sendQueuedGo()

                    if self.ignoreNext:
                        log.debug(
                            "__parseLine: line='%s' self.ignoreNext==True, returning" % line.strip(),
                            extra={"task": self.defname})
                        self.ignoreNext = False
                        self.readyForStop = True
                        continue

                    movestr = parts[1]
                    if not self.waitingForMove:
                        log.warning("__parseLine: self.waitingForMove==False, ignoring move=%s" % movestr,
                                    extra={"task": self.defname})
                        self.pondermove = None
                        continue
                    self.waitingForMove = False

                    try:
                        move = parseAny(self.board, movestr)
                    except ParsingError:
                        self.invalid_move = movestr
                        self.end(WHITEWON if self.board.color == BLACK else
                                 BLACKWON, WON_ADJUDICATION)
                        continue

                    if not validate(self.board, move):
                        # This is critical. To avoid game stalls, we need to resign on
                        # behalf of the engine.
                        log.error("__parseLine: move=%s didn't validate, putting 'del' \
                                  in returnQueue. self.board=%s" % (
                            repr(move), self.board), extra={"task": self.defname})
                        self.invalid_move = movestr
                        self.end(WHITEWON if self.board.color == BLACK else
                                 BLACKWON, WON_ADJUDICATION)
                        continue

                    self._recordMove(self.board.move(move), move, self.board)
                    log.debug("__parseLine: applied move=%s to self.board=%s" % (
                        move, self.board), extra={"task": self.defname})

                    if self.ponderOn:
                        self.pondermove = None
                        # An engine may send an empty ponder line, simply to clear.
                        if len(parts) == 4:
                            # Engines don't always check for everything in their
                            # ponders. Hence we need to validate.
                            # But in some cases, what they send may not even be
                            # correct AN - specially in the case of promotion.
                            try:
                                pondermove = parseAny(self.board, parts[3])
                            except ParsingError:
                                pass
                            else:
                                if validate(self.board, pondermove):
                                    self.pondermove = pondermove
                                    self._startPonder()

                    self.queue.put_nowait(move)
                    log.debug("__parseLine: put move=%s into self.queue=%s" % (
                        move, self.queue), extra={"task": self.defname})
                    continue

                # An Analysis
                if self.mode != NORMAL and parts[0] == "info" and "pv" in parts:
                    multipv = 1
                    if "multipv" in parts:
                        multipv = int(parts[parts.index("multipv") + 1])
                    scoretype = parts[parts.index("score") + 1]
                    if scoretype in ('lowerbound', 'upperbound'):
                        score = None
                    else:
                        score = int(parts[parts.index("score") + 2])
                        if scoretype == 'mate':
                            #                    print >> self.engine, "stop"
                            if score != 0:
                                sign = score / abs(score)
                                score = sign * MATE_VALUE

                    movstrs = parts[parts.index("pv") + 1:]

                    if "depth" in parts:
                        depth = parts[parts.index("depth") + 1]
                    else:
                        depth = ""

                    if multipv <= len(self.analysis):
                        self.analysis[multipv - 1] = (movstrs, score, depth)

                    self.emit("analyze", self.analysis)
                    continue

                # An Analyzer bestmove
                if self.mode != NORMAL and parts[0] == "bestmove":
                    log.debug("__parseLine: processing analyzer bestmove='%s'" % line.strip(),
                              extra={"task": self.defname})
                    self.needBestmove = False
                    self.__sendQueuedGo(sendlast=True)
                    continue

                # Stockfish complaining it received a 'stop' without a corresponding 'position..go'
                if line.strip() == "Unknown command: stop":
                    log.debug("__parseLine: processing '%s'" % line.strip(),
                              extra={"task": self.defname})
                    self.ignoreNext = False
                    self.needBestmove = False
                    self.readyForStop = False
                    self.__sendQueuedGo()
                    continue
Ejemplo n.º 10
0
                def analyse_moves():
                    should_black = conf.get("shouldBlack")
                    should_white = conf.get("shouldWhite")
                    from_current = conf.get("fromCurrent")
                    start_ply = gmwidg.board.view.shown if from_current else 0
                    move_time = int(conf.get("max_analysis_spin"))
                    threshold = int(conf.get("variation_threshold_spin"))
                    for board in gamemodel.boards[start_ply:]:
                        if self.stop_event.is_set():
                            break

                        gmwidg.board.view.setShownBoard(board)
                        analyzer.setBoard(board)
                        if threat_PV:
                            inv_analyzer.setBoard(board)
                        yield from asyncio.sleep(move_time + 0.1)

                        ply = board.ply - gamemodel.lowply
                        color = (ply - 1) % 2
                        if ply - 1 in gamemodel.scores and ply in gamemodel.scores and (
                                (color == BLACK and should_black) or (color == WHITE and should_white)):
                            oldmoves, oldscore, olddepth = gamemodel.scores[ply - 1]
                            oldscore = oldscore * -1 if color == BLACK else oldscore
                            score_str = prettyPrintScore(oldscore, olddepth)
                            moves, score, depth = gamemodel.scores[ply]
                            score = score * -1 if color == WHITE else score
                            diff = score - oldscore
                            if ((diff > threshold and color == BLACK) or (diff < -1 * threshold and color == WHITE)) and (
                               gamemodel.moves[ply - 1] != parseAny(gamemodel.boards[ply - 1], oldmoves[0])):
                                if threat_PV:
                                    try:
                                        if ply - 1 in gamemodel.spy_scores:
                                            oldmoves0, oldscore0, olddepth0 = gamemodel.spy_scores[ply - 1]
                                            score_str0 = prettyPrintScore(oldscore0, olddepth0)
                                            pv0 = listToMoves(gamemodel.boards[ply - 1], ["--"] + oldmoves0, validate=True)
                                            if len(pv0) > 2:
                                                gamemodel.add_variation(gamemodel.boards[ply - 1], pv0,
                                                                        comment="Threatening", score=score_str0, emit=False)
                                    except ParsingError as e:
                                        # ParsingErrors may happen when parsing "old" lines from
                                        # analyzing engines, which haven't yet noticed their new tasks
                                        log.debug("__parseLine: Ignored (%s) from analyzer: ParsingError%s" %
                                                  (' '.join(oldmoves), e))
                                try:
                                    pv = listToMoves(gamemodel.boards[ply - 1], oldmoves, validate=True)
                                    gamemodel.add_variation(gamemodel.boards[ply - 1], pv,
                                                            comment="Better is", score=score_str, emit=False)
                                except ParsingError as e:
                                    # ParsingErrors may happen when parsing "old" lines from
                                    # analyzing engines, which haven't yet noticed their new tasks
                                    log.debug("__parseLine: Ignored (%s) from analyzer: ParsingError%s" %
                                              (' '.join(oldmoves), e))

                    self.widgets["analyze_game"].hide()
                    self.widgets["analyze_ok_button"].set_sensitive(True)
                    conf.set("analyzer_check", old_check_value)
                    if threat_PV:
                        conf.set("inv_analyzer_check", old_inv_check_value)
                    message.dismiss()

                    gamemodel.emit("analysis_finished")
Ejemplo n.º 11
0
    def __parseLine (self, line):
        if line[0:1] == "#":
            # Debug line which we shall ignore as specified in CECPv2 specs
            return

#        log.debug("__parseLine: line=\"%s\"\n" % line.strip(), self.defname)
        parts = whitespaces.split(line.strip())
        
        if parts[0] == "pong":
            self.lastpong = int(parts[1])
            return
        
        # Illegal Move
        if parts[0].lower().find("illegal") >= 0:
            log.warn("__parseLine: illegal move: line=\"%s\", board=%s" \
                % (line.strip(), self.board), self.defname)
            if parts[-2] == "sd" and parts[-1].isdigit():
                print >> self.engine, "depth", parts[-1] 
            return
        
        # A Move (Perhaps)
        if self.board:
            if parts[0] == "move":
                movestr = parts[1]
            # Old Variation
            elif d_plus_dot_expr.match(parts[0]) and parts[1] == "...":
                movestr = parts[2]
            else:
                movestr = False
            
            if movestr:
                log.debug("__parseLine: acquiring self.boardLock\n", self.defname)
                self.waitingForMove = False
                self.readyForMoveNowCommand = False
                self.boardLock.acquire()
                try:
                    if self.engineIsInNotPlaying:
                        # If engine was set in pause just before the engine sent its
                        # move, we ignore it. However the engine has to know that we
                        # ignored it, and thus we step it one back
                        log.info("__parseLine: Discarding engine's move: %s\n" % movestr, self.defname)
                        print >> self.engine, "undo"
                        return
                    else:
                        try:
                            move = parseAny(self.board, movestr)
                        except ParsingError, e:
                            self.end(WHITEWON if self.board.color == BLACK else BLACKWON, WON_ADJUDICATION)
                            return
                        
                        if validate(self.board, move):
                            self.board = None
                            self.returnQueue.put(move)
                            return
                        self.end(WHITEWON if self.board.color == BLACK else BLACKWON, WON_ADJUDICATION)
                        return
                finally:
                    log.debug("__parseLine(): releasing self.boardLock\n", self.defname)
                    self.boardLock.release()
                    self.movecon.acquire()
                    self.movecon.notifyAll()
                    self.movecon.release()
        
        # Analyzing
        if self.engineIsInNotPlaying:
            if parts[:4] == ["0","0","0","0"]:
                # Crafty doesn't analyze until it is out of book
                print >> self.engine, "book off"
                return
            
            match = anare.match(line)
            if match:
                score, moves = match.groups()
                
                if "mat" in score.lower() or "#" in moves:
                    # Will look either like -Mat 3 or Mat3
                    scoreval = MATE_VALUE
                    if score.startswith('-'):
                        scoreval = -scoreval
                else:
                    scoreval = int(score)
                
                mvstrs = movere.findall(moves)
                try:
                    moves = listToMoves (self.board, mvstrs, type=None, validate=True, ignoreErrors=False)
                except:
                    # Errors may happen when parsing "old" lines from
                    # analyzing engines, which haven't yet noticed their new tasks
                    log.debug('Ignored an "old" line from analyzer: %s\n' % mvstrs, self.defname)
                    return
                
                # Don't emit if we weren't able to parse moves, or if we have a move
                # to kill the opponent king - as it confuses many engines
                if moves and not self.board.board.opIsChecked():
                    #self.emit("analyze", [(moves, scoreval)])
                
                return
        
        # Offers draw
        if parts[0:2] == ["offer", "draw"]:
            #self.emit("accept", Offer(DRAW_OFFER))
            return
        
        # Resigns
        if parts[0] == "resign" or \
            (parts[0] == "tellics" and parts[1] == "resign"): # buggy crafty

            # Previously: if "resign" in parts,
            # however, this is too generic, since "hint", "bk",
            # "feature option=.." and possibly other, future CECPv2
            # commands can validly contain the word "resign" without this
            # being an intentional resign offer.

            #self.emit("offer", Offer(RESIGNATION))
            return
        
        #if parts[0].lower() == "error":
        #    return
        
        #Tell User Error
        if parts[0] == "tellusererror":
            # Create a non-modal non-blocking message dialog with the error:
            dlg = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING, buttons=gtk.BUTTONS_CLOSE, message_format=None)

            # Use the engine name if already known, otherwise the defname:
            displayname = self.name
            if not displayname:
                displayname = self.defname

            # Compose the dialog text:
            dlg.set_markup(gobject.markup_escape_text(_("The engine %s reports an error:") % displayname) + "\n\n" + gobject.markup_escape_text(" ".join(parts[1:])))

            # handle response signal so the "Close" button works:
            dlg.connect("response", lambda dlg, x: dlg.destroy())

            dlg.show_all()
            return
        
        # Tell Somebody
        if parts[0][:4] == "tell" and \
                parts[0][4:] in ("others", "all", "ics", "icsnoalias"):
            
            log.info("Ignoring tell %s: %s\n" % (parts[0][4:], " ".join(parts[1:])))
            return
        
        if "feature" in parts:
            # Some engines send features after done=1, so we will iterate after done=1 too
            done1 = False
            # We skip parts before 'feature', as some engines give us lines like
            # White (1) : feature setboard=1 analyze...e="GNU Chess 5.07" done=1
            parts = parts[parts.index("feature"):]
            for i, pair in enumerate(parts[1:]):
                
                # As "parts" is split with no thoughs on quotes or double quotes
                # we need to do some extra handling.
                
                if pair.find("=") < 0: continue
                key, value = pair.split("=",1)
                
                if value[0] in ('"',"'") and value[-1] in ('"',"'"):
                    value = value[1:-1]
                
                # If our pair was unfinished, like myname="GNU, we search the
                # rest of the pairs for a quotating mark.
                elif value[0] in ('"',"'"):
                    rest = value[1:] + " " + " ".join(parts[2+i:])
                    i = rest.find('"')
                    j = rest.find("'")
                    if i + j == -2:
                        log.warn("Missing endquotation in %s feature", self.defname)
                        value = rest
                    elif min(i, j) != -1:
                        value = rest[:min(i, j)]
                    else:
                        l = max(i, j)
                        value = rest[:l]
                
                elif value.isdigit():
                    value = int(value)
                
                if key in self.supported_features:
                    print >> self.engine, "accepted %s" % key
                else:
                    print >> self.engine, "rejected %s" % key
                
                if key == "done":
                    if value == 1:
                        done1 = True
                        continue
                    elif value == 0:
                        log.info("Adds %d seconds timeout\n" % TIME_OUT_SECOND, self.defname)
                        # This'll buy you some more time
                        self.timeout = time.time()+TIME_OUT_SECOND
                        self.returnQueue.put("not ready")
                        return
                
                if key == "smp" and value == 1:
                    self.options["cores"] = {"name": "cores", "type": "spin", "default": 1, "min": 1, "max": 64}
                elif key == "memory" and value == 1:
                    self.options["memory"] = {"name": "memory", "type": "spin", "default": 32, "min": 1, "max": 4096}
                elif key == "option" and key != "done":
                    option = self.__parse_option(value)
                    self.options[option["name"]] = option
                else:
                    self.features[key] = value

                if key == "myname" and not self.name:
                    self.setName(value)
        
            if done1:
                # Start a new game before using the engine:
                # (CECPv2 engines)
                print >> self.engine, "new"

                # We are now ready for play:
                #self.emit("readyForOptions")
                #self.emit("readyForMoves")
                self.returnQueue.put("ready")

        # A hack to get better names in protover 1.
        # Unfortunately it wont work for now, as we don't read any lines from
        # protover 1 engines. When should we stop?
        if self.protover == 1:
            if self.defname[0] in ''.join(parts):
                basis = self.defname[0]
                name = ' '.join(itertools.dropwhile(lambda part: basis not in part, parts))
                self.features['myname'] = name
                if not self.name:
                    self.setName(name)

    def __parse_option(self, option):
        if " -check " in option:
            name, value = option.split(" -check ")
            return {"type": "check", "name": name, "default": bool(int(value))}
        elif " -spin " in option:
            name, value = option.split(" -spin ")
            defv, minv, maxv = value.split()
            return {"type": "spin", "name": name, "default": int(defv), "min": int(minv), "max": int(maxv)}
        elif " -slider " in option:
            name, value = option.split(" -slider ")
            defv, minv, maxv = value.split()
            return {"type": "spin", "name": name, "default": int(defv), "min": int(minv), "max": int(maxv)}
        elif " -string " in option:
            name, value = option.split(" -string ")
            return {"type": "text", "name": name, "default": value}
        elif " -file " in option:
            name, value = option.split(" -file ")
            return {"type": "text", "name": name, "default": value}
        elif " -path " in option:
            name, value = option.split(" -path ")
            return {"type": "text", "name": name, "default": value}
        elif " -combo " in option:
            name, value = option.split(" -combo ")
            return {"type": "combo", "name": name, "default": value}
        elif " -button" in option:
            pos = option.find(" -button")
            return {"type": "button", "name": option[:pos]}
        elif " -save" in option:
            pos = option.find(" -save")
            return {"type": "button", "name": option[:pos]}
        elif " -reset" in option:
            pos = option.find(" -reset")
            return {"type": "button", "name": option[:pos]}

    #===========================================================================
    #    Info
    #===========================================================================
    
    def canAnalyze (self):
        assert self.ready, "Still waiting for done=1"
        return self.features["analyze"]
    
    def maxAnalysisLines (self):
        return 1
    
    def requestMultiPV (self, setting):
        return 1
    
    def isAnalyzing (self):
        return self.mode in (ANALYZING, INVERSE_ANALYZING)
    
    def __repr__ (self):
        if self.name:
            return self.name
        return self.features["myname"]
Ejemplo n.º 12
0
    def coro(gamemodel, steps):
        exit_lecture = False
        inside_bsetup = False
        paused = False
        moves_played = 0

        KIBITZ, BACKWARD, BSETUP, BSETUP_DONE, FEN, TOMOVE, WCASTLE, BCASTLE, \
            WNAME, BNAME, REVERT, WAIT, MOVE = range(13)

        while True:
            try:
                step = next(steps)
                print(step)

                parts = step.strip().split()

                command = None
                param = ""

                if parts[0] == "k" or parts[0] == "kibitz":
                    command = KIBITZ
                    param = " ".join(parts[1:])
                elif parts[0] == "back":
                    command = BACKWARD
                    param = int(parts[1]) if len(parts) > 1 else 1
                elif parts[0] == "bsetup":
                    if len(parts) == 1:
                        command = BSETUP
                    else:
                        if parts[1] == "done":
                            command = BSETUP_DONE
                        elif parts[1] == "fen":
                            command = FEN
                            param = parts[2]
                        elif parts[1] == "tomove":
                            command = TOMOVE
                            param = "w" if parts[2].lower()[0] == "w" else "b"
                        elif parts[1] == "wcastle":
                            command = WCASTLE
                            param = parts[2]
                        elif parts[1] == "bcastle":
                            command = BCASTLE
                            param = parts[2]
                elif parts[0] == "tomove":
                    command = TOMOVE
                    param = "w" if parts[1].lower()[0] == "w" else "b"
                elif parts[0] == "wname":
                    command = WNAME
                    param = parts[1]
                elif parts[0] == "bname":
                    command = BNAME
                    param = parts[1]
                elif parts[0] == "revert":
                    command = REVERT
                elif len(parts) == 1 and parts[0].isdigit():
                    command = WAIT
                    param = int(parts[0])
                else:
                    command = MOVE
                    param = parts[0]

                if not inside_bsetup and command == BSETUP:
                    inside_bsetup = True
                    pieces = ""
                    color = ""
                    castl = ""
                    ep = ""
                elif inside_bsetup and command == BSETUP_DONE:
                    inside_bsetup = False

                wait_sec = int(param) if command == WAIT else 2

                if inside_bsetup:
                    wait_sec = -1

                while wait_sec >= 0:
                    if gamemodel.lecture_exit_event.is_set():
                        gamemodel.lecture_exit_event.clear()
                        exit_lecture = True
                        break

                    if gamemodel.lecture_skip_event.is_set():
                        gamemodel.lecture_skip_event.clear()
                        paused = False
                        break

                    if gamemodel.lecture_pause_event.is_set():
                        gamemodel.lecture_pause_event.clear()
                        paused = True

                    yield from asyncio.sleep(0.1)
                    if not paused:
                        wait_sec = wait_sec - 0.1

                if exit_lecture:
                    gamemodel.players[0].putMessage("Lecture exited.")
                    break

                if command != WAIT:
                    if command == KIBITZ:
                        gamemodel.players[0].putMessage(param)
                    if command == BACKWARD:
                        gamemodel.undoMoves(param)
                        moves_played -= param
                    if command == MOVE:
                        board = gamemodel.getBoardAtPly(gamemodel.ply)
                        move = parseAny(board, param)
                        gamemodel.curplayer.move_queue.put_nowait(move)
                        moves_played += 1
                    elif command == REVERT:
                        gamemodel.undoMoves(moves_played)
                        moves_played = 0
                    elif command == BNAME:
                        gamemodel.players[BLACK].name = param
                        gamemodel.emit("players_changed")
                    elif command == WNAME:
                        gamemodel.players[WHITE].name = param
                        gamemodel.emit("players_changed")
                    elif command == FEN:
                        pieces = param
                    elif command == TOMOVE:
                        color = param
                    elif command == WCASTLE:
                        if param == "both":
                            castl += "KQ"
                        elif param == "kside":
                            castl += "K"
                        elif param == "qside":
                            castl += "Q"
                    elif command == BCASTLE:
                        if param == "both":
                            castl += "kq"
                        elif param == "kside":
                            castl += "k"
                        elif param == "qside":
                            castl += "q"
                    elif command == BSETUP_DONE:
                        if not castl:
                            castl = "-"
                        if not ep:
                            ep = "-"
                        fen = "%s %s %s %s 0 1" % (pieces, color, castl, ep)

                        curplayer = gamemodel.curplayer
                        gamemodel.status = RUNNING
                        gamemodel.loadAndStart(
                            StringIO(fen),
                            fen_loader,
                            0,
                            -1,
                            first_time=False)
                        curplayer.move_queue.put_nowait("int")
                        gamemodel.emit("game_started")
                        moves_played = 0

            except StopIteration:
                # connection.client.run_command("kibitz That concludes this lecture.")
                break