Exemplo n.º 1
0
 def __go(self):
     if self.worker:
         self.worker.cancel()
     self.worker = GtkWorker(
         lambda worker: PyChess._PyChess__go(self, worker))
     self.worker.connect("published", lambda w, msg: self.extendlog(msg))
     self.worker.connect("done", self.__onMoveCalculated)
     self.worker.execute()
Exemplo n.º 2
0
 def __go (self):
     if self.worker:
         self.worker.cancel()
     self.worker = GtkWorker(lambda worker: PyChess._PyChess__go(self, worker))
     self.worker.connect("published", lambda w, msg: self.extendlog(msg))
     self.worker.connect("done", self.__onMoveCalculated)
     self.worker.execute()
Exemplo n.º 3
0
class PyChessFICS(PyChess):
    def __init__ (self, password, from_address, to_address):
        PyChess.__init__(self)
        
        self.ports = (23, 5000)
        if not password:
            self.username = "******"
        else: self.username = "******"
        self.owner = "Lobais"
        self.password = password
        self.from_address = "The PyChess Bot <%s>" % from_address
        self.to_address = "Thomas Dybdahl Ahle <%s>" % to_address
        
        # Possible start times
        self.minutes = (1,2,3,4,5,6,7,8,9,10)
        self.gains = (0,5,10,15,20)
        # Possible colors. None == random
        self.colors = (WHITE, BLACK, None) 
        # The amount of random challenges, that PyChess sends with each seek
        self.challenges = 10
        enableEGTB()
        
        self.sudos = set()
        self.ownerOnline = False
        self.waitingForPassword = None
        self.log = []
        self.acceptedTimesettings = []
        
        self.worker = None
        
        repeat_sleep(self.sendChallenges, 60*1)
    
    def __triangular(self, low, high, mode):
        """Triangular distribution.
        Continuous distribution bounded by given lower and upper limits,
        and having a given mode value in-between.
        http://en.wikipedia.org/wiki/Triangular_distribution
        """
        u = random.random()
        c = (mode - low) / (high - low)
        if u > c:
            u = 1 - u
            c = 1 - c
            low, high = high, low
        tri = low + (high - low) * (u * c) ** 0.5
        if tri < mode:
            return int(tri)
        elif tri > mode:
            return int(math.ceil(tri))
        return int(round(tri))
    
    def sendChallenges(self):
        if self.connection.bm.isPlaying():
            return True
        
        statsbased = ((0.39197722779282, 3, 0),
                      (0.59341408108783, 5, 0),
                      (0.77320877377846, 1, 0),
                      (0.8246379941394, 10, 0),
                      (0.87388717406441, 2, 12),
                      (0.91443760169489, 15, 0),
                      (0.9286423058163, 4, 0),
                      (0.93891977227793, 2, 0),
                      (0.94674539138335, 20, 0),
                      (0.95321476842423, 2, 2),
                      (0.9594588808257, 5, 2),
                      (0.96564528079889, 3, 2),
                      (0.97173859621034, 7, 0),
                      (0.97774906636184, 3, 1),
                      (0.98357243654425, 5, 12),
                      (0.98881309737017, 5, 5),
                      (0.99319644938247, 6, 0),
                      (0.99675879556023, 3, 12),
                      (1, 5, 3))
        
        #n = random.random()
        #for culminativeChance, minute, gain in statsbased:
        #    if n < culminativeChance:
        #        break
        
        culminativeChance, minute, gain = random.choice(statsbased)
        
        #type = random.choice((TYPE_LIGHTNING, TYPE_BLITZ, TYPE_STANDARD))
        #if type == TYPE_LIGHTNING:
        #    minute = self.__triangular(0,2+1,1)
        #    mingain = not minute and 1 or 0
        #    maxgain = int((3-minute)*3/2)
        #    gain = random.randint(mingain, maxgain)
        #elif type == TYPE_BLITZ:
        #    minute = self.__triangular(0,14+1,5)
        #    mingain = max(int((3-minute)*3/2+1), 0)
        #    maxgain = int((15-minute)*3/2)
        #    gain = random.randint(mingain, maxgain)
        #elif type == TYPE_STANDARD:
        #    minute = self.__triangular(0,20+1,12)
        #    mingain = max(int((15-minute)*3/2+1), 0)
        #    maxgain = int((20-minute)*3/2)
        #    gain = self.__triangular(mingain, maxgain, mingain)
        
        #color = random.choice(self.colors)
        self.extendlog(["Seeking %d %d" % (minute, gain)])
        self.connection.glm.seek(minute, gain, True)
        opps = random.sample(self.connection.players.get_online_playernames(),
                             self.challenges)
        self.extendlog("Challenging %s" % op for op in opps)
        for player in opps:
            self.connection.om.challenge(player, minute, gain, True)
        
        return True
    
    def makeReady(self):
        signal.signal(signal.SIGINT, Gtk.main_quit)
        
        PyChess.makeReady(self)
        
        self.connection = FICSMainConnection("freechess.org", self.ports,
                                             self.username, self.password)
        self.connection.connect("connectingMsg", self.__showConnectLog)
        self.connection._connect()
        
        self.connection.glm.connect("addPlayer", self.__onAddPlayer)
        self.connection.glm.connect("removePlayer", self.__onRemovePlayer)
        self.connection.cm.connect("privateMessage", self.__onTell)
        self.connection.alm.connect("logOut", self.__onLogOut)
        self.connection.bm.connect("playGameCreated", self.__onGameCreated)
        self.connection.bm.connect("curGameEnded", self.__onGameEnded)
        self.connection.bm.connect("boardUpdate", self.__onBoardUpdate)
        self.connection.om.connect("onChallengeAdd", self.__onChallengeAdd)
        self.connection.om.connect("onOfferAdd", self.__onOfferAdd)
        self.connection.adm.connect("onAdjournmentsList", self.__onAdjournmentsList)
        self.connection.em.connect("onAmbiguousMove", self.__onAmbiguousMove)
        self.connection.em.connect("onIllegalMove", self.__onAmbiguousMove)
        
        self.connection.adm.queryAdjournments()
        self.connection.lvm.setVariable("autoflag", 1)
        
        self.connection.fm.setFingerNote(1,
            "PyChess is the chess engine bundled with the PyChess %s " % pychess.VERSION +
            "chess client. This instance is owned by %s, but acts " % self.owner +
            "quite autonomously.")
        
        self.connection.fm.setFingerNote(2,
            "PyChess is 100% Python code and is released under the terms of " +
            "the GPL. The evalution function is largely equal to the one of" +
            "GnuChess, but it plays quite differently.")
        
        self.connection.fm.setFingerNote(3,
            "PyChess runs on an elderly AMD Sempron(tm) Processor 3200+, 512 " +
            "MB DDR2 Ram, but is built to take use of 64bit calculating when " +
            "accessible, through the gpm library.")
        
        self.connection.fm.setFingerNote(4,
            "PyChess uses a small 500 KB openingbook based solely on Kasparov " +
            "games. The engine doesn't have much endgame knowledge, but might " +
            "in some cases access an online endgamedatabase.")
        
        self.connection.fm.setFingerNote(5,
            "PyChess will allow any pause/resume and adjourn wishes, but will " +
            "deny takebacks. Draw, abort and switch offers are accepted, " +
            "if they are found to be an advance. Flag is auto called, but " +
            "PyChess never resigns. We don't want you to forget your basic " +
            "mating skills.")
    
    def main(self):
        self.connection.run()
        self.extendlog([str(self.acceptedTimesettings)])
        self.phoneHome("Session ended\n"+"\n".join(self.log))
        print("Session ended")
    
    def run(self):
        t = Thread(target=self.main, name=fident(self.main))
        t.daemon = True
        t.start()
        Gdk.threads_init()
        Gtk.main()
    
    #===========================================================================
    # General
    #===========================================================================
    
    def __showConnectLog (self, connection, message):
        print(message)
    
    def __onLogOut (self, autoLogoutManager):
        self.connection.close()
        #sys.exit()
    
    def __onAddPlayer (self, gameListManager, player):
        if player["name"] in self.sudos:
            self.sudos.remove(player["name"])
        if player["name"] == self.owner:
            self.connection.cm.tellPlayer(self.owner, "Greetings")
            self.ownerOnline = True
    
    def __onRemovePlayer (self, gameListManager, playername):
        if playername == self.owner:
            self.ownerOnline = False
    
    def __onAdjournmentsList (self, adjournManager, adjournments):
        for adjournment in adjournments:
            if adjournment["online"]:
                adjournManager.challenge(adjournment["opponent"])
    
    def __usage (self):
        return "|| PyChess bot help file || " +\
               "# help 'Displays this help file' " +\
               "# sudo <password> <command> 'Lets PyChess execute the given command' "+\
               "# sendlog 'Makes PyChess send you its current log'"
    
    def __onTell (self, chatManager, name, title, isadmin, text):
        
        if self.waitingForPassword:
            if text.strip() == self.password or (not self.password and text == "none"):
                self.sudos.add(name)
                self.tellHome("%s gained sudo access" % name)
                self.connection.client.run_command(self.waitingForPassword)
            else:
                chatManager.tellPlayer(name, "Wrong password")
                self.tellHome("%s failed sudo access" % name)
            self.waitingForPassword = None
            return
        
        args = text.split()
        
        #if args == ["help"]:
        #    chatManager.tellPlayer(name, self.__usage())
        
        if args[0] == "sudo":
            command = " ".join(args[1:])
            if name in self.sudos or name == self.owner:
                # Notice: This can be used to make nasty loops
                print(command, file=self.connection.client)
            else:
                print(repr(name), self.sudos)
                chatManager.tellPlayer(name, "Please send me the password")
                self.waitingForPassword = command
        
        elif args == ["sendlog"]:
            if self.log:
                # TODO: Consider email
                chatManager.tellPlayer(name, "\\n".join(self.log))
            else:
                chatManager.tellPlayer(name, "The log is currently empty")
        
        else:
            if self.ownerOnline:
                self.tellHome("%s told me '%s'" % (name, text))
            else:
                def onlineanswer (message):
                    data = urlopen("http://www.pandorabots.com/pandora/talk?botid=8d034368fe360895",
                                   urlencode({"message":message, "botcust2":"x"}).encode("utf-8")).read().decode('utf-8')
                    ss = "<b>DMPGirl:</b>"
                    es = "<br>"
                    answer = data[data.find(ss)+len(ss) : data.find(es,data.find(ss))]
                    chatManager.tellPlayer(name, answer)
                t = Thread(target=onlineanswer,
                           name=fident(onlineanswer),
                           args=(text,))
                t.daemon = True
                t.start()
            #chatManager.tellPlayer(name, "Sorry, your request was nonsense.\n"+\
            #                           "Please read my help file for more info")
    
    #===========================================================================
    # Challenges and other offers
    #===========================================================================
    
    def __onChallengeAdd (self, offerManager, index, match):
        #match = {"tp": type, "w": fname, "rt": rating, "color": color,
        #         "r": rated, "t": mins, "i": incr}
        offerManager.acceptIndex(index)
    
    def __onOfferAdd (self, offerManager, offer):
        if offer.type in (PAUSE_OFFER, RESUME_OFFER, ADJOURN_OFFER):
            offerManager.accept(offer)
        elif offer.type in (TAKEBACK_OFFER,):
            offerManager.decline(offer)
        elif offer.type in (DRAW_OFFER, ABORT_OFFER, SWITCH_OFFER):
            if self.__willingToDraw():
                offerManager.accept(offer)
            else: offerManager.decline(offer)
    
    #===========================================================================
    # Playing
    #===========================================================================
    
    def __onGameCreated (self, boardManager, ficsgame):
        
        base = int(ficsgame.minutes)*60
        inc = int(ficsgame.inc)
        self.clock[:] = base, base
        self.increment[:] = inc, inc
        self.gameno = ficsgame.gameno
        self.lastPly = -1
        
        self.acceptedTimesettings.append((base, inc))
        
        self.tellHome("Starting a game (%s, %s) gameno: %s" %
                (ficsgame.wplayer.name, ficsgame.bplayer.name, ficsgame.gameno))
        
        if ficsgame.bplayer.name.lower() == self.connection.getUsername().lower():
            self.playingAs = BLACK
        else:
            self.playingAs = WHITE
        
        self.board = LBoard(NORMALCHESS)
        # Now we wait until we recieve the board.
    
    def __go (self):
        if self.worker:
            self.worker.cancel()
        self.worker = GtkWorker(lambda worker: PyChess._PyChess__go(self, worker))
        self.worker.connect("published", lambda w, msg: self.extendlog(msg))
        self.worker.connect("done", self.__onMoveCalculated)
        self.worker.execute()

    def __willingToDraw (self):
        return self.scr <= 0 # FIXME: this misbehaves in all but the simplest use cases
    
    def __onGameEnded (self, boardManager, ficsgame):
        self.tellHome(reprResult_long[ficsgame.result] + " " + reprReason_long[ficsgame.reason])
        lsearch.searching = False
        if self.worker:
            self.worker.cancel()
            self.worker = None
    
    def __onMoveCalculated (self, worker, sanmove):
        if worker.isCancelled() or not sanmove:
            return
        self.board.applyMove(parseSAN(self.board,sanmove))
        self.connection.bm.sendMove(sanmove)
        self.extendlog(["Move sent %s" % sanmove])
    
    def __onBoardUpdate (self, boardManager, gameno, ply, curcol, lastmove, fen, wname, bname, wms, bms):
        self.extendlog(["","I got move %d %s for gameno %s" % (ply, lastmove, gameno)])
        
        if self.gameno != gameno:
            return
        
        self.board.applyFen(fen)
        
        self.clock[:] = wms/1000., bms/1000.
        
        if curcol == self.playingAs:
            self.__go()
    
    def __onAmbiguousMove (self, errorManager, move):
        # This is really a fix for fics, but sometimes it is necessary
        if determineAlgebraicNotation(move) == SAN:
            self.board.popMove()
            move_ = parseSAN(self.board, move)
            lanmove = toLAN(self.board, move_)
            self.board.applyMove(move_)
            self.connection.bm.sendMove(lanmove)
        else:
            self.connection.cm.tellOpponent(
                    "I'm sorry, I wanted to move %s, but FICS called " % move +
                    "it 'Ambigious'. I can't find another way to express it, " +
                    "so you can win")
            self.connection.bm.resign()
    
    #===========================================================================
    # Utils
    #===========================================================================
    
    def extendlog(self, messages):
        [log.info(m+"\n") for m in messages]
        self.log.extend(messages)
        del self.log[:-10]
    
    def tellHome(self, message):
        print(message)
        if self.ownerOnline:
            self.connection.cm.tellPlayer(self.owner, message)
    
    def phoneHome(self, message):
        
        SENDMAIL = '/usr/sbin/sendmail'
        SUBJECT = "Besked fra botten"
        
        p = subprocess.Popen([SENDMAIL, '-f',
                              email.Utils.parseaddr(self.from_address)[1],
                              email.Utils.parseaddr(self.to_address)[1]],
                              stdin=subprocess.PIPE)
        
        print("MIME-Version: 1.0", file=p.stdin)
        print("Content-Type: text/plain; charset=UTF-8", file=p.stdin)
        print("Content-Disposition: inline", file=p.stdin)
        print("From: %s" % self.from_address, file=p.stdin)
        print("To: %s" % self.to_address, file=p.stdin)
        print("Subject: %s" % SUBJECT, file=p.stdin)
        print(file=p.stdin)
        print(message, file=p.stdin)
        print("Cheers", file=p.stdin)
        
        p.stdin.close()
        p.wait()
Exemplo n.º 4
0
class PyChessFICS(PyChess):
    def __init__(self, password, from_address, to_address):
        PyChess.__init__(self)

        self.ports = (23, 5000)
        if not password:
            self.username = "******"
        else:
            self.username = "******"
        self.owner = "Lobais"
        self.password = password
        self.from_address = "The PyChess Bot <%s>" % from_address
        self.to_address = "Thomas Dybdahl Ahle <%s>" % to_address

        # Possible start times
        self.minutes = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
        self.gains = (0, 5, 10, 15, 20)
        # Possible colors. None == random
        self.colors = (WHITE, BLACK, None)
        # The amount of random challenges, that PyChess sends with each seek
        self.challenges = 10
        enableEGTB()

        self.sudos = set()
        self.ownerOnline = False
        self.waitingForPassword = None
        self.log = []
        self.acceptedTimesettings = []

        self.worker = None

        repeat_sleep(self.sendChallenges, 60 * 1)

    def __triangular(self, low, high, mode):
        """Triangular distribution.
        Continuous distribution bounded by given lower and upper limits,
        and having a given mode value in-between.
        http://en.wikipedia.org/wiki/Triangular_distribution
        """
        u = random.random()
        c = (mode - low) / (high - low)
        if u > c:
            u = 1 - u
            c = 1 - c
            low, high = high, low
        tri = low + (high - low) * (u * c)**0.5
        if tri < mode:
            return int(tri)
        elif tri > mode:
            return int(math.ceil(tri))
        return int(round(tri))

    def sendChallenges(self):
        if self.connection.bm.isPlaying():
            return True

        statsbased = ((0.39197722779282, 3, 0), (0.59341408108783, 5, 0),
                      (0.77320877377846, 1, 0), (0.8246379941394, 10, 0),
                      (0.87388717406441, 2, 12), (0.91443760169489, 15, 0),
                      (0.9286423058163, 4, 0), (0.93891977227793, 2,
                                                0), (0.94674539138335, 20, 0),
                      (0.95321476842423, 2, 2), (0.9594588808257, 5,
                                                 2), (0.96564528079889, 3, 2),
                      (0.97173859621034, 7, 0), (0.97774906636184, 3,
                                                 1), (0.98357243654425, 5, 12),
                      (0.98881309737017, 5, 5), (0.99319644938247, 6,
                                                 0), (0.99675879556023, 3,
                                                      12), (1, 5, 3))

        #n = random.random()
        #for culminativeChance, minute, gain in statsbased:
        #    if n < culminativeChance:
        #        break

        culminativeChance, minute, gain = random.choice(statsbased)

        #type = random.choice((TYPE_LIGHTNING, TYPE_BLITZ, TYPE_STANDARD))
        #if type == TYPE_LIGHTNING:
        #    minute = self.__triangular(0,2+1,1)
        #    mingain = not minute and 1 or 0
        #    maxgain = int((3-minute)*3/2)
        #    gain = random.randint(mingain, maxgain)
        #elif type == TYPE_BLITZ:
        #    minute = self.__triangular(0,14+1,5)
        #    mingain = max(int((3-minute)*3/2+1), 0)
        #    maxgain = int((15-minute)*3/2)
        #    gain = random.randint(mingain, maxgain)
        #elif type == TYPE_STANDARD:
        #    minute = self.__triangular(0,20+1,12)
        #    mingain = max(int((15-minute)*3/2+1), 0)
        #    maxgain = int((20-minute)*3/2)
        #    gain = self.__triangular(mingain, maxgain, mingain)

        #color = random.choice(self.colors)
        self.extendlog(["Seeking %d %d" % (minute, gain)])
        self.connection.glm.seek(minute, gain, True)
        opps = random.sample(self.connection.players.get_online_playernames(),
                             self.challenges)
        self.extendlog("Challenging %s" % op for op in opps)
        for player in opps:
            self.connection.om.challenge(player, minute, gain, True)

        return True

    def makeReady(self):
        signal.signal(signal.SIGINT, Gtk.main_quit)

        PyChess.makeReady(self)

        self.connection = FICSMainConnection("freechess.org", self.ports,
                                             self.username, self.password)
        self.connection.connect("connectingMsg", self.__showConnectLog)
        self.connection._connect()

        self.connection.glm.connect("addPlayer", self.__onAddPlayer)
        self.connection.glm.connect("removePlayer", self.__onRemovePlayer)
        self.connection.cm.connect("privateMessage", self.__onTell)
        self.connection.alm.connect("logOut", self.__onLogOut)
        self.connection.bm.connect("playGameCreated", self.__onGameCreated)
        self.connection.bm.connect("curGameEnded", self.__onGameEnded)
        self.connection.bm.connect("boardUpdate", self.__onBoardUpdate)
        self.connection.om.connect("onChallengeAdd", self.__onChallengeAdd)
        self.connection.om.connect("onOfferAdd", self.__onOfferAdd)
        self.connection.adm.connect("onAdjournmentsList",
                                    self.__onAdjournmentsList)
        self.connection.em.connect("onAmbiguousMove", self.__onAmbiguousMove)
        self.connection.em.connect("onIllegalMove", self.__onAmbiguousMove)

        self.connection.adm.queryAdjournments()
        self.connection.lvm.setVariable("autoflag", 1)

        self.connection.fm.setFingerNote(
            1, "PyChess is the chess engine bundled with the PyChess %s " %
            pychess.VERSION +
            "chess client. This instance is owned by %s, but acts " %
            self.owner + "quite autonomously.")

        self.connection.fm.setFingerNote(
            2,
            "PyChess is 100% Python code and is released under the terms of " +
            "the GPL. The evalution function is largely equal to the one of" +
            "GnuChess, but it plays quite differently.")

        self.connection.fm.setFingerNote(
            3,
            "PyChess runs on an elderly AMD Sempron(tm) Processor 3200+, 512 "
            +
            "MB DDR2 Ram, but is built to take use of 64bit calculating when "
            + "accessible, through the gpm library.")

        self.connection.fm.setFingerNote(
            4,
            "PyChess uses a small 500 KB openingbook based solely on Kasparov "
            +
            "games. The engine doesn't have much endgame knowledge, but might "
            + "in some cases access an online endgamedatabase.")

        self.connection.fm.setFingerNote(
            5,
            "PyChess will allow any pause/resume and adjourn wishes, but will "
            + "deny takebacks. Draw, abort and switch offers are accepted, " +
            "if they are found to be an advance. Flag is auto called, but " +
            "PyChess never resigns. We don't want you to forget your basic " +
            "mating skills.")

    def main(self):
        self.connection.run()
        self.extendlog([str(self.acceptedTimesettings)])
        self.phoneHome("Session ended\n" + "\n".join(self.log))
        print("Session ended")

    def run(self):
        t = Thread(target=self.main, name=fident(self.main))
        t.daemon = True
        t.start()
        Gdk.threads_init()
        Gtk.main()

    #===========================================================================
    # General
    #===========================================================================

    def __showConnectLog(self, connection, message):
        print(message)

    def __onLogOut(self, autoLogoutManager):
        self.connection.close()
        #sys.exit()

    def __onAddPlayer(self, gameListManager, player):
        if player["name"] in self.sudos:
            self.sudos.remove(player["name"])
        if player["name"] == self.owner:
            self.connection.cm.tellPlayer(self.owner, "Greetings")
            self.ownerOnline = True

    def __onRemovePlayer(self, gameListManager, playername):
        if playername == self.owner:
            self.ownerOnline = False

    def __onAdjournmentsList(self, adjournManager, adjournments):
        for adjournment in adjournments:
            if adjournment["online"]:
                adjournManager.challenge(adjournment["opponent"])

    def __usage(self):
        return "|| PyChess bot help file || " +\
               "# help 'Displays this help file' " +\
               "# sudo <password> <command> 'Lets PyChess execute the given command' "+\
               "# sendlog 'Makes PyChess send you its current log'"

    def __onTell(self, chatManager, name, title, isadmin, text):

        if self.waitingForPassword:
            if text.strip() == self.password or (not self.password
                                                 and text == "none"):
                self.sudos.add(name)
                self.tellHome("%s gained sudo access" % name)
                self.connection.client.run_command(self.waitingForPassword)
            else:
                chatManager.tellPlayer(name, "Wrong password")
                self.tellHome("%s failed sudo access" % name)
            self.waitingForPassword = None
            return

        args = text.split()

        #if args == ["help"]:
        #    chatManager.tellPlayer(name, self.__usage())

        if args[0] == "sudo":
            command = " ".join(args[1:])
            if name in self.sudos or name == self.owner:
                # Notice: This can be used to make nasty loops
                print(command, file=self.connection.client)
            else:
                print(repr(name), self.sudos)
                chatManager.tellPlayer(name, "Please send me the password")
                self.waitingForPassword = command

        elif args == ["sendlog"]:
            if self.log:
                # TODO: Consider email
                chatManager.tellPlayer(name, "\\n".join(self.log))
            else:
                chatManager.tellPlayer(name, "The log is currently empty")

        else:
            if self.ownerOnline:
                self.tellHome("%s told me '%s'" % (name, text))
            else:

                def onlineanswer(message):
                    data = urlopen(
                        "http://www.pandorabots.com/pandora/talk?botid=8d034368fe360895",
                        urlencode({
                            "message": message,
                            "botcust2": "x"
                        }).encode("utf-8")).read().decode('utf-8')
                    ss = "<b>DMPGirl:</b>"
                    es = "<br>"
                    answer = data[data.find(ss) +
                                  len(ss):data.find(es, data.find(ss))]
                    chatManager.tellPlayer(name, answer)

                t = Thread(target=onlineanswer,
                           name=fident(onlineanswer),
                           args=(text, ))
                t.daemon = True
                t.start()
            #chatManager.tellPlayer(name, "Sorry, your request was nonsense.\n"+\
            #                           "Please read my help file for more info")

    #===========================================================================
    # Challenges and other offers
    #===========================================================================

    def __onChallengeAdd(self, offerManager, index, match):
        #match = {"tp": type, "w": fname, "rt": rating, "color": color,
        #         "r": rated, "t": mins, "i": incr}
        offerManager.acceptIndex(index)

    def __onOfferAdd(self, offerManager, offer):
        if offer.type in (PAUSE_OFFER, RESUME_OFFER, ADJOURN_OFFER):
            offerManager.accept(offer)
        elif offer.type in (TAKEBACK_OFFER, ):
            offerManager.decline(offer)
        elif offer.type in (DRAW_OFFER, ABORT_OFFER, SWITCH_OFFER):
            if self.__willingToDraw():
                offerManager.accept(offer)
            else:
                offerManager.decline(offer)

    #===========================================================================
    # Playing
    #===========================================================================

    def __onGameCreated(self, boardManager, ficsgame):

        base = int(ficsgame.minutes) * 60
        inc = int(ficsgame.inc)
        self.clock[:] = base, base
        self.increment[:] = inc, inc
        self.gameno = ficsgame.gameno
        self.lastPly = -1

        self.acceptedTimesettings.append((base, inc))

        self.tellHome(
            "Starting a game (%s, %s) gameno: %s" %
            (ficsgame.wplayer.name, ficsgame.bplayer.name, ficsgame.gameno))

        if ficsgame.bplayer.name.lower() == self.connection.getUsername(
        ).lower():
            self.playingAs = BLACK
        else:
            self.playingAs = WHITE

        self.board = LBoard(NORMALCHESS)
        # Now we wait until we recieve the board.

    def __go(self):
        if self.worker:
            self.worker.cancel()
        self.worker = GtkWorker(
            lambda worker: PyChess._PyChess__go(self, worker))
        self.worker.connect("published", lambda w, msg: self.extendlog(msg))
        self.worker.connect("done", self.__onMoveCalculated)
        self.worker.execute()

    def __willingToDraw(self):
        return self.scr <= 0  # FIXME: this misbehaves in all but the simplest use cases

    def __onGameEnded(self, boardManager, ficsgame):
        self.tellHome(reprResult_long[ficsgame.result] + " " +
                      reprReason_long[ficsgame.reason])
        lsearch.searching = False
        if self.worker:
            self.worker.cancel()
            self.worker = None

    def __onMoveCalculated(self, worker, sanmove):
        if worker.isCancelled() or not sanmove:
            return
        self.board.applyMove(parseSAN(self.board, sanmove))
        self.connection.bm.sendMove(sanmove)
        self.extendlog(["Move sent %s" % sanmove])

    def __onBoardUpdate(self, boardManager, gameno, ply, curcol, lastmove, fen,
                        wname, bname, wms, bms):
        self.extendlog(
            ["",
             "I got move %d %s for gameno %s" % (ply, lastmove, gameno)])

        if self.gameno != gameno:
            return

        self.board.applyFen(fen)

        self.clock[:] = wms / 1000., bms / 1000.

        if curcol == self.playingAs:
            self.__go()

    def __onAmbiguousMove(self, errorManager, move):
        # This is really a fix for fics, but sometimes it is necessary
        if determineAlgebraicNotation(move) == SAN:
            self.board.popMove()
            move_ = parseSAN(self.board, move)
            lanmove = toLAN(self.board, move_)
            self.board.applyMove(move_)
            self.connection.bm.sendMove(lanmove)
        else:
            self.connection.cm.tellOpponent(
                "I'm sorry, I wanted to move %s, but FICS called " % move +
                "it 'Ambigious'. I can't find another way to express it, " +
                "so you can win")
            self.connection.bm.resign()

    #===========================================================================
    # Utils
    #===========================================================================

    def extendlog(self, messages):
        [log.info(m + "\n") for m in messages]
        self.log.extend(messages)
        del self.log[:-10]

    def tellHome(self, message):
        print(message)
        if self.ownerOnline:
            self.connection.cm.tellPlayer(self.owner, message)

    def phoneHome(self, message):

        SENDMAIL = '/usr/sbin/sendmail'
        SUBJECT = "Besked fra botten"

        p = subprocess.Popen([
            SENDMAIL, '-f',
            email.Utils.parseaddr(self.from_address)[1],
            email.Utils.parseaddr(self.to_address)[1]
        ],
                             stdin=subprocess.PIPE)

        print("MIME-Version: 1.0", file=p.stdin)
        print("Content-Type: text/plain; charset=UTF-8", file=p.stdin)
        print("Content-Disposition: inline", file=p.stdin)
        print("From: %s" % self.from_address, file=p.stdin)
        print("To: %s" % self.to_address, file=p.stdin)
        print("Subject: %s" % SUBJECT, file=p.stdin)
        print(file=p.stdin)
        print(message, file=p.stdin)
        print("Cheers", file=p.stdin)

        p.stdin.close()
        p.wait()