Beispiel #1
0
def generalStart (gamemodel, player0tup, player1tup, loaddata=None):
    """ The player tuples are:
        (The type af player in a System.const value,
         A callable creating the player,
         A list of arguments for the callable,
         A preliminary name for the player)

        If loaddata is specified, it should be a tuple of:
        (A text uri or fileobj,
         A Savers.something module with a load function capable of loading it,
         An int of the game in file you want to load,
         The position from where to start the game) """
    log.debug("ionest.generalStart: %s\n %s\n %s\n" % (gamemodel, player0tup, player1tup))
    worker = GtkWorker (lambda w:
            workfunc(w, gamemodel, player0tup, player1tup, loaddata))

    def onPublished (worker, vallist):
        for val in vallist:
            # The worker will start by publishing (gmwidg, game)
            if type(val) == tuple:
                gmwidg, game = val
                gamewidget.attachGameWidget(gmwidg)
                gamenanny.nurseGame(gmwidg, game)
                handler.emit("gmwidg_created", gmwidg, game)

            # Then the worker will publish functions setting up widget stuff
            elif callable(val):
                val()
    worker.connect("published", onPublished)

    def onDone (worker, (gmwidg, game)):
        gmwidg.connect("close_clicked", closeGame, game)
        worker.__del__()
Beispiel #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()
Beispiel #3
0
 def __go (self):
     self.worker = GtkWorker(lambda worker: PyChess._PyChess__go(self, worker))
     def process (worker, messages): print "\n".join(messages)
     self.worker.connect("published", process)
     def ondone (worker, result):
         if not result: return
         self.board.applyMove(parseSAN(self.board,result))
         print "move %s" % result
     self.worker.connect("done", ondone)
     self.worker.execute()
def generalStart(gamemodel, player0tup, player1tup, loaddata=None):
    """ The player tuples are:
        (The type af player in a System.const value,
         A callable creating the player,
         A list of arguments for the callable,
         A preliminary name for the player)

        If loaddata is specified, it should be a tuple of:
        (A text uri or fileobj,
         A Savers.something module with a load function capable of loading it,
         An int of the game in file you want to load,
         The position from where to start the game) """
    log.debug("ionest.generalStart: %s\n %s\n %s\n" %
              (gamemodel, player0tup, player1tup))
    worker = GtkWorker(
        lambda w: workfunc(w, gamemodel, player0tup, player1tup, loaddata))

    def onPublished(worker, vallist):
        for val in vallist:
            # The worker will start by publishing (gmwidg, game)
            if type(val) == tuple:
                gmwidg, game = val
                gamewidget.attachGameWidget(gmwidg)
                gamenanny.nurseGame(gmwidg, game)
                handler.emit("gmwidg_created", gmwidg, game)

            # Then the worker will publish functions setting up widget stuff
            elif callable(val):
                val()

    worker.connect("published", onPublished)

    def onDone(worker, (gmwidg, game)):
        gmwidg.connect("close_clicked", closeGame, game)
        worker.__del__()
Beispiel #5
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
        self.useegtb = True
        
        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(math.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.glm.getPlayerlist(), 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):
        PyChess.makeReady(self)
        
        self.connection = FICSConnection("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("playBoardCreated", self.__onPlayBoardCreated)
        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", True)
        
        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 run(self):
        self.connection.run()
        self.extendlog([str(self.acceptedTimesettings)])
        self.phoneHome("Session ended\n"+"\n".join(self.log))
        print "Session ended"
    
    #===========================================================================
    # 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)
                print >> self.connection.client, 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 >> self.connection.client, command
            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"})).read()
                    ss = "<b>DMPGirl:</b>"
                    es = "<br>"
                    answer = data[data.find(ss)+len(ss) : data.find(es,data.find(ss))]
                    chatManager.tellPlayer(name, answer)
                pool.start(onlineanswer, text)
            #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, "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.scr <= 0:
                offerManager.accept(offer)
            else: offerManager.decline(offer)
    
    #===========================================================================
    # Playing
    #===========================================================================
    
    def __onPlayBoardCreated (self, boardManager, board):
        
        self.mytime = int(board["mins"])*60
        self.increment = int(board["incr"])
        self.gameno = board["gameno"]
        self.lastPly = -1
        
        self.acceptedTimesettings.append((self.mytime, self.increment))
        
        self.tellHome("Starting a game (%s, %s) gameno: %s" %
                (board["wname"], board["bname"], board["gameno"]))
        
        if board["bname"].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 __onGameEnded (self, boardManager, gameno, wname, bname, result, reason):
        self.tellHome(reprResult_long[result] + " " + reprReason_long[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)
        
        if self.playingAs == WHITE:
            self.mytime = wms/1000.
        else: self.mytime = 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.log(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 >> p.stdin, "MIME-Version: 1.0"
        print >> p.stdin, "Content-Type: text/plain; charset=UTF-8"
        print >> p.stdin, "Content-Disposition: inline"
        print >> p.stdin, "From: %s" % self.from_address
        print >> p.stdin, "To: %s" % self.to_address
        print >> p.stdin, "Subject: %s" % SUBJECT
        print >> p.stdin
        print >> p.stdin, message
        print >> p.stdin, "Cheers"
        
        p.stdin.close()
        p.wait()
Beispiel #6
0
 def __analyze (self):
     self.worker = GtkWorker(lambda worker: PyChess._PyChess__analyze(self, worker))
     def process (worker, messages): print "\n".join(messages)
     self.worker.connect("published", process)
     self.worker.execute()
Beispiel #7
0
class PyChessCECP(PyChess):
    
    def __init__ (self):
        PyChess.__init__(self)
        self.board = LBoard(NORMALCHESS)
        self.board.applyFen(FEN_START)
        
        self.forced = False
        self.analyzing = False
        self.worker = None
        
        self.features = {
            "setboard": 1,
            "analyze": 1,
            "san": 1,
            "usermove": 1,
            "reuse": 0,
            "draw": 1,
            "sigterm": 1,
            "colors": 1,
            "variants": "normal,nocastle,fischerandom",
            "myname": "PyChess %s" % pychess.VERSION
        }
    
    def makeReady(self):
        PyChess.makeReady(self)
    
    def run (self):
        while True:
            line = raw_input()
            if not line.strip(): continue
            lines = line.split()
            
            if lines[0] == "protover":
                stringPairs = ["=".join([k,repr(v)]) for k,v in self.features.iteritems()]
                print "feature %s done=1" % " ".join(stringPairs)
            
            elif lines[0] == "usermove":
                
                self.__stopSearching()
                
                move = parseAny (self.board, lines[1])
                
                if not validateMove(self.board, move):
                    print "Illegal move", lines[1]
                    continue
                
                self.board.applyMove(move)
                
                self.playingAs = self.board.color
                
                if not self.forced and not self.analyzing:
                    self.__go()
                
                if self.analyzing:
                    self.__analyze()
            
            elif lines[0] == "sd":
                self.sd = int(lines[1])
                self.skipPruneChance = max(0, (5-self.sd)*0.02)
                if self.sd >= 5:
                    print "If the game has no timesettings, you probably don't want\n"+\
                          "to set a search depth much greater than 4"
            
            elif lines[0] == "egtb":
                # This is a crafty command interpreted a bit loose
                self.useegtb = True
            
            elif lines[0] == "level":
                moves = int(lines[1])
                self.increment = int(lines[3])
                minutes = lines[2].split(":")
                self.mytime = int(minutes[0])*60
                if len(minutes) > 1:
                    self.mytime += int(minutes[1])
                print "Playing %d moves in %d seconds + %d increment" % \
                        (moves, self.mytime, self.increment)
            
            elif lines[0] == "time":
                self.mytime = int(lines[1])/100.
            
            #elif lines[0] == "otim":
            #   self.optime = int(lines[1])
            
            elif lines[0] == "quit":
                sys.exit()
            
            elif lines[0] == "result":
                # We don't really care what the result is at the moment.
                sys.exit()
            
            elif lines[0] == "force":
                if not self.forced and not self.analyzing:
                    self.forced = True
                    self.__stopSearching()
            
            elif lines[0] == "go":
                self.playingAs = self.board.color
                self.forced = False
                self.__go()
            
            elif lines[0] == "undo":
                self.__stopSearching()
                self.board.popMove()
                if self.analyzing:
                    self.__analyze()
            
            elif lines[0] == "?":
                self.__stopSearching()
            
            elif lines[0] in ("black", "white"):
                newColor = lines[0] == "black" and BLACK or WHITE
                if self.playingAs != newColor:
                    self.__stopSearching()
                    self.playingAs = newColor
                    # It is dangerous to use the same table, when we change color
                    #lsearch.table.clear()
                    self.board.setColor(newColor)
                    # Concider the case:
                    # * White moves a pawn and creates a enpassant cord
                    # * Spy analyzer is not set back to white to analyze the
                    #   position. An attackable enpassant cord now no longer makes
                    #   sense.
                    # * Notice though, that when the color is shifted back to black
                    #   to make the actual move - and it is an enpassant move - the
                    #   cord won't be set in the lboard.
                    self.board.setEnpassant(None)
                    if self.analyzing:
                        self.__analyze()
            
            elif lines[0] == "analyze":
                self.playingAs = self.board.color
                self.analyzing = True
                self.__analyze()
                
            elif lines[0] == "draw":
                if self.scr <= 0:
                    print "offer draw"
                
            elif lines[0] == "random":
                leval.random = True
            
            elif lines[0] == "variant":
                if lines[1] == "fischerandom":
                    self.board.variant = FISCHERRANDOMCHESS
                
            elif lines[0] == "setboard":
                self.__stopSearching()
                self.board.applyFen(" ".join(lines[1:]))
                if self.analyzing:
                    self.__analyze()
            
            elif lines[0] in ("xboard", "otim", "hard", "easy", "nopost", "post",
                              "accepted", "rejected"):
                pass
            
            else: print "Warning (unknown command):", line
    
    def __stopSearching(self):
        lsearch.searching = False
        if self.worker:
            self.worker.cancel()
            glock.acquire()
            self.worker.get()
            glock.release()
            self.worker = None
    
    def __go (self):
        self.worker = GtkWorker(lambda worker: PyChess._PyChess__go(self, worker))
        def process (worker, messages): print "\n".join(messages)
        self.worker.connect("published", process)
        def ondone (worker, result):
            if not result: return
            self.board.applyMove(parseSAN(self.board,result))
            print "move %s" % result
        self.worker.connect("done", ondone)
        self.worker.execute()
    
    def __analyze (self):
        self.worker = GtkWorker(lambda worker: PyChess._PyChess__analyze(self, worker))
        def process (worker, messages): print "\n".join(messages)
        self.worker.connect("published", process)
        self.worker.execute()