예제 #1
0
    def on_icc_offers_in_my_game(self, data):
        log.debug("DG_OFFERS_IN_MY_GAME %s" % data)
        # gamenumber wdraw bdraw wadjourn badjourn wabort babort wtakeback btakeback
        gamenumber, wdraw, bdraw, wadjourn, badjourn, wabort, babort, wtakeback, btakeback = map(
            int, data.split())

        if wdraw or bdraw:
            offertype = DRAW_OFFER
        elif wadjourn or badjourn:
            offertype = ADJOURN_OFFER
        elif wabort or babort:
            offertype = ABORT_OFFER
        elif wtakeback or btakeback:
            offertype = TAKEBACK_OFFER
        else:
            log.debug(
                "ICCOfferManager.on_icc_offers_in_my_game: unknown offer data: %s"
                % data)
            return

        index = gamenumber * 100000 + OFFERS.index(offertype)
        if offertype == TAKEBACK_OFFER:
            parameters = wtakeback if wtakeback else btakeback
            offer = Offer(offertype, param=parameters, index=index)
        else:
            offer = Offer(offertype, index=index)
        self.offers[offer.index] = offer

        log.debug(
            "ICCOfferManager.on_icc_offers_in_my_game: emitting onOfferAdd: %s"
            % offer)
        self.emit("onOfferAdd", offer)
    def __init__(self, connection):
        GObject.GObject.__init__(self)

        self.connection = connection

        self.connection.expect_line(
            self.onOfferAdd, "<p(t|f)> (\d+) w=%s t=(\w+) p=(.+)" % names)
        self.connection.expect_line(self.onOfferRemove, "<pr> (\d+)")

        for ficsstring, offer, error in (
            (
                "You cannot switch sides once a game is underway.",
                Offer(SWITCH_OFFER),
                ACTION_ERROR_SWITCH_UNDERWAY,
            ),
            (
                "Opponent is not out of time.",
                Offer(FLAG_CALL),
                ACTION_ERROR_NOT_OUT_OF_TIME,
            ),
            (
                "The clock is not ticking yet.",
                Offer(PAUSE_OFFER),
                ACTION_ERROR_CLOCK_NOT_STARTED,
            ),
            (
                "The clock is not ticking.",
                Offer(FLAG_CALL),
                ACTION_ERROR_CLOCK_NOT_STARTED,
            ),
            (
                "The clock is not paused.",
                Offer(RESUME_OFFER),
                ACTION_ERROR_CLOCK_NOT_PAUSED,
            ),
        ):
            self.connection.expect_line(
                lambda match: self.emit("onActionError", offer, error),
                ficsstring)

        self.connection.expect_line(
            self.notEnoughMovesToUndo,
            "There are (?:(no)|only (\d+) half) moves in your game\.",
        )

        self.connection.expect_line(
            self.noOffersToAccept, "There are no ([^ ]+) offers to (accept).")

        self.connection.expect_line(
            self.onOfferDeclined,
            "\w+ declines the (draw|takeback|pause|unpause|abort|adjourn) request\.",
        )

        self.lastPly = 0
        self.offers = {}

        self.connection.client.run_command("iset pendinfo 1")
예제 #3
0
    def end(self, status, reason):
        if self.status in UNFINISHED_STATES:
            self.__disconnect()

            if self.inControl:
                self.connection.om.offer(Offer(ABORT_OFFER), -1)
                self.connection.om.offer(Offer(RESIGNATION), -1)
            else:
                self.connection.bm.unobserve(self.gameno)

        GameModel.end(self, status, reason)
예제 #4
0
 def callback (infobar, response, message):
     if response == 1:
         # newGameDialog uses ionest uses gamenanny uses newGameDialog...
         from pychess.widgets.newGameDialog import createRematch
         createRematch(gamemodel)
     elif response == 2:
         if gamemodel.ply > 1:
             offer = Offer(TAKEBACK_OFFER, gamemodel.ply-2)
         else:
             offer = Offer(TAKEBACK_OFFER, gamemodel.ply-1)
         if gamemodel.players[0].__type__ == LOCAL:
             gamemodel.players[0].emit("offer", offer)
         else: gamemodel.players[1].emit("offer", offer)
     return False
예제 #5
0
    def end(self, status, reason):
        if self.status in UNFINISHED_STATES:
            self.__disconnect()

            if self.isObservationGame():
                self.connection.bm.unobserve(self.ficsgame)
            else:
                self.connection.om.offer(Offer(ABORT_OFFER), -1)
                self.connection.om.offer(Offer(RESIGNATION), -1)

        if status == KILLED:
            GameModel.kill(self, reason)
        else:
            GameModel.end(self, status, reason)
예제 #6
0
    def onOfferAdd(self, match):
        log.debug("OfferManager.onOfferAdd: match.string=%s\n" % match.string)
        tofrom, index, offertype, parameters = match.groups()
        if tofrom == "t":
            # ICGameModel keeps track of the offers we've sent ourselves, so we
            # don't need this
            return
        if offertype not in strToOfferType:
            log.error("OfferManager.onOfferAdd: Declining unknown offer type: " + \
                "offertype=%s parameters=%s index=%s\n" % (offertype, parameters, index))
            print >> self.connection.client, "decline", index
        offertype = strToOfferType[offertype]
        if offertype == TAKEBACK_OFFER:
            offer = Offer(offertype, param=int(parameters), index=int(index))
        else:
            offer = Offer(offertype, index=int(index))
        self.offers[offer.index] = offer

        if offer.type == MATCH_OFFER:
            if matchreUntimed.match(parameters) != None:
                fname, frating, col, tname, trating, rated, type = \
                    matchreUntimed.match(parameters).groups()
                mins = "0"
                incr = "0"
            else:
                fname, frating, col, tname, trating, rated, type_short, mins, incr, type = \
                    matchre.match(parameters).groups()
                if not type or "adjourned" in type:
                    type = type_short

            if type.split()[-1] in unsupportedtypes:
                self.decline(offer)
            else:
                rating = frating.strip()
                rating = rating.isdigit() and rating or "0"
                rated = rated == "unrated" and "u" or "r"
                match = {
                    "tp": convertName(type),
                    "w": fname,
                    "rt": rating,
                    "r": rated,
                    "t": mins,
                    "i": incr
                }
                self.emit("onChallengeAdd", index, match)

        else:
            log.debug("OfferManager.onOfferAdd: emitting onOfferAdd: %s\n" %
                      offer)
            self.emit("onOfferAdd", offer)
예제 #7
0
 def zero_reached(self, timemodel, color):
     if conf.get('autoCallFlag', False) and \
             self.gamemodel.status == RUNNING and \
             timemodel.getPlayerTime(1-self.color) <= 0:
         log.log('Automatically sending flag call on behalf of player %s.' %
                 self.name)
         self.emit("offer", Offer(FLAG_CALL))
예제 #8
0
 def offerError(self, offer, error):
     if self.features["draw"]:
         # We don't keep track if engine draws are offers or accepts. We just
         # Always assume they are accepts, and if they are not, we get this
         # error and emit offer instead
         if offer.type == DRAW_OFFER and error == ACTION_ERROR_NONE_TO_ACCEPT:
             self.emit("offer", Offer(DRAW_OFFER))
예제 #9
0
 def zero_reached(self, timemodel, color):
     if conf.get('autoCallFlag'):
         if self.status == RUNNING and timemodel.getPlayerTime(color) <= 0:
             log.info(
                 'Automatically sending flag call on behalf of player %s.' %
                 self.players[1 - color].name)
             self.players[1 - color].emit("offer", Offer(FLAG_CALL))
예제 #10
0
 def notEnoughMovesToUndo(self, match):
     ply = match.groups()[0] or match.groups()[1]
     if ply == "no":
         ply = 0
     else:
         ply = int(ply)
     offer = Offer(TAKEBACK_OFFER, param=ply)
     self.emit("onActionError", offer, ACTION_ERROR_TOO_LARGE_UNDO)
예제 #11
0
 def cb(messageDialog, responseId):
     if responseId == 0:
         if gamemodel.players[0].__type__ == REMOTE:
             gamemodel.players[0].offerRematch()
         else:
             gamemodel.players[1].offerRematch()
     elif responseId == 1:
         from pychess.widgets.newGameDialog import createRematch
         createRematch(gamemodel)
     elif responseId == 2:
         if gamemodel.curplayer.__type__ == LOCAL and gamemodel.ply > 1:
             offer = Offer(TAKEBACK_OFFER, gamemodel.ply - 2)
         else:
             offer = Offer(TAKEBACK_OFFER, gamemodel.ply - 1)
         if gamemodel.players[0].__type__ == LOCAL:
             gamemodel.players[0].emit("offer", offer)
         else:
             gamemodel.players[1].emit("offer", offer)
예제 #12
0
 def noOffersToAccept(self, match):
     offertype, request = match.groups()
     if request == "accept":
         error = ACTION_ERROR_NONE_TO_ACCEPT
     elif request == "withdraw":
         error = ACTION_ERROR_NONE_TO_WITHDRAW
     elif request == "decline":
         error = ACTION_ERROR_NONE_TO_DECLINE
     offer = Offer(strToOfferType[offertype])
     self.emit("onActionError", offer, error)
예제 #13
0
 def zero_reached(self, timemodel, color):
     if (
         conf.get("autoCallFlag")
         and self.gamemodel.status == RUNNING
         and timemodel.getPlayerTime(1 - self.color) <= 0
     ):
         log.info(
             "Automatically sending flag call on behalf of player %s." % self.name
         )
         self.emit("offer", Offer(FLAG_CALL))
예제 #14
0
 def answer (message):
     try:
         data = urlopen("http://www.pandorabots.com/pandora/talk?botid=8d034368fe360895",
                        urlencode({"message":message, "botcust2":"x"}).encode("utf-8")).read().decode('utf-8')
     except IOError as e:
         log.warning("Couldn't answer message from online bot: '%s'" % e,
                  extra={"task":self.defname})
         return
     ss = "<b>DMPGirl:</b>"
     es = "<br>"
     answer = data[data.find(ss)+len(ss) : data.find(es,data.find(ss))]
     self.emit("offer", Offer(CHAT_ACTION, answer))
예제 #15
0
 def emit_action(self, action, param):
     # If there are two or more tabs open, we have to ensure us that it is
     # us who are in the active tab, and not the others
     if self.gmwidg != cur_gmwidg():
         return
     # If there are two human players, we have to ensure us that it was us
     # who did the action, and not the others
     if self.gamemodel.players[1 - self.color].__type__ == LOCAL:
         if action == HURRY_ACTION:
             if self.gamemodel.boards[-1].color == self.color:
                 return
         else:
             if self.gamemodel.boards[-1].color != self.color:
                 return
     self.emit("offer", Offer(action, param=param))
예제 #16
0
 def emit_action (self, action, param):
     # If there are two or more tabs open, we have to ensure us that it is
     # us who are in the active tab, and not the others
     if not self.gmwidg.isInFront(): return
     log.debug("Human.emit_action: self.name=%s, action=%s" % (self.name, action))
     
     # If there are two human players, we have to ensure us that it was us
     # who did the action, and not the others
     if self.gamemodel.players[1-self.color].__type__ == LOCAL:
         if action == HURRY_ACTION:
             if self.gamemodel.boards[-1].color == self.color:
                 return
         else:
             if self.gamemodel.boards[-1].color != self.color:
                 return
     self.emit("offer", Offer(action, param=param))
예제 #17
0
 def putMessage(self, message):
     def answer(message):
         try:
             data = urlopen(
                 "http://www.pandorabots.com/pandora/talk?botid=8d034368fe360895",
                 urlencode({
                     "message": message,
                     "botcust2": "x"
                 })).read()
         except IOError, e:
             log.warn("Couldn't answer message from online bot: '%s'\n" % e,
                      self.defname)
             return
         ss = "<b>DMPGirl:</b>"
         es = "<br>"
         answer = data[data.find(ss) + len(ss):data.find(es, data.find(ss))]
         self.emit("offer", Offer(CHAT_ACTION, answer))
예제 #18
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)
예제 #19
0
 def emit_action(board, action, param, gmwidg):
     if gmwidg.isInFront():
         gamemodel.curplayer.emit("offer", Offer(action, param=param))
예제 #20
0
    def onOfferAdd(self, match):
        log.debug("OfferManager.onOfferAdd: match.string=%s" % match.string)

        tofrom, index, offertype, parameters = match.groups()
        index = int(index)

        if tofrom == "t":
            # ICGameModel keeps track of the offers we've sent ourselves, so we
            # don't need this
            return
        if offertype not in strToOfferType:
            log.warning("OfferManager.onOfferAdd: Declining unknown offer type: " +
                        "offertype=%s parameters=%s index=%d" % (offertype, parameters, index))
            self.connection.client.run_command("decline %d" % index)
            return
        offertype = strToOfferType[offertype]
        if offertype == TAKEBACK_OFFER:
            offer = Offer(offertype, param=int(parameters), index=index)
        else:
            offer = Offer(offertype, index=index)
        self.offers[offer.index] = offer

        if offer.type == MATCH_OFFER:
            is_adjourned = False
            if matchreUntimed.match(parameters) is not None:
                fname, frating, col, tname, trating, rated, type = \
                    matchreUntimed.match(parameters).groups()
                mins = 0
                incr = 0
                gametype = GAME_TYPES["untimed"]
            else:
                fname, frating, col, tname, trating, rated, gametype, mins, \
                    incr, wildtype, adjourned = matchre.match(parameters).groups()
                if (wildtype and "adjourned" in wildtype) or \
                        (adjourned and "adjourned" in adjourned):
                    is_adjourned = True
                if wildtype and "wild" in wildtype:
                    gametype = wildtype

                try:
                    gametype = GAME_TYPES[gametype]
                except KeyError:
                    log.warning("OfferManager.onOfferAdd: auto-declining " +
                                "unknown offer type: '%s'\n" % gametype)
                    self.decline(offer)
                    del self.offers[offer.index]
                    return

            player = self.connection.players.get(fname)
            rating = frating.strip()
            rating = int(rating) if rating.isdigit() else 0
            if player.ratings[gametype.rating_type] != rating:
                player.ratings[gametype.rating_type] = rating
                player.emit("ratings_changed", gametype.rating_type, player)
            rated = rated != "unrated"
            challenge = FICSChallenge(index,
                                      player,
                                      int(mins),
                                      int(incr),
                                      rated,
                                      col,
                                      gametype,
                                      adjourned=is_adjourned)
            self.emit("onChallengeAdd", challenge)

        else:
            log.debug("OfferManager.onOfferAdd: emitting onOfferAdd: %s" %
                      offer)
            self.emit("onOfferAdd", offer)
예제 #21
0
 def __onPrivateMessage(self, cm, name, title, isadmin, text):
     if name == self.ichandle:
         self.emit("offer", Offer(CHAT_ACTION, param=text))
예제 #22
0
 def sendMessage (self, text):
     self.emit("offer", Offer(CHAT_ACTION, param=text))
예제 #23
0
 def onOfferDeclined(self, match):
     log.debug("OfferManager.onOfferDeclined: match.string=%s" %
               match.string)
     type = match.groups()[0]
     offer = Offer(strToOfferType[type])
     self.emit("onOfferDeclined", offer)