def removeFromRumble(self, requests):
    #global global_dict
    global_dict = {}
    if "version" not in requests or requests["version"] is not "1":
        return "ERROR. bad/no version"

    game = requests.get("game", None)
    if game is None:
        return "ERROR. no game specified"

    name = requests.get("name", None)
    if name is None:
        return "ERROR. no name specified"
    while name.count("%20") > 0:
        name = rreplace(name, "%20", " ", 1)

    rumble = global_dict.get(game, None)
    if rumble is None:
        rumble = memcache.get(game)
        if rumble is None:
            rumble = structures.Rumble.get_by_key_name(game)

    entry = None
    if name.count(" ") == 0:
        num_underscores = name.count("_")
        error_messages = []
        for n in range(num_underscores):
            check_name = nth_repl(name, "_", " ", n + 1)

            keyhash = check_name + "|" + game
            entry = global_dict.get(keyhash, None)
            if entry is None:
                entry = memcache.get(keyhash)
                if entry is None:
                    entry = structures.BotEntry.get_by_key_name(keyhash)
                    if entry is None:
                        error_messages.append(
                            "ERROR. name/game does not exist: " + check_name +
                            "/" + game)
                    else:
                        entry = structures.CachedBotEntry(entry)

            if entry is not None:
                name = check_name
                break
        if entry is None:
            return "\n".join(error_messages)
    else:
        return "ERROR. Bot name missing version."

    if isinstance(entry, structures.BotEntry):
        entry = structures.CachedBotEntry(entry)

    global_dict.pop(keyhash, 0)
    memcache.delete(keyhash)

    entry.Active = False

    try:
        scores = pickle.loads(zlib.decompress(rumble.ParticipantsScores))
    except:
        scoresdicts = marshal.loads(zlib.decompress(rumble.ParticipantsScores))
        scoreslist = [structures.LiteBot() for _ in scoresdicts]
        for s, d in zip(scoreslist, scoresdicts):
            s.__dict__.update(d)
        scores = {s.Name: s for s in scoreslist}

    scores.pop(name, 1)
    rumble.ParticipantsScores = zlib.compress(
        pickle.dumps(scores, pickle.HIGHEST_PROTOCOL), 4)

    memcache.delete("home")
    global_dict.pop("home", 0)

    memcache.set(entry.key_name, entry)
    global_dict[entry.key_name] = entry
    modelBot = structures.BotEntry(key_name=entry.key_name)
    modelBot.init_from_cache(entry)
    modelBot.put()

    global_dict[game] = rumble
    memcache.set(game, rumble)
    rumble.put()

    return "OK. " + name + " retired from " + game
Пример #2
0
    def get(self):
        #global global_dict
        global_dict = {}
        starttime = time.time()
        query = self.request.query_string
        query = query.replace("%20"," ")
        parts = query.split("&")
        requests = {}
        if parts[0] != "":
            for pair in parts:
                ab = pair.split('=')
                requests[ab[0]] = ab[1]
            
        game = requests.get("game","meleerumble")
        lim = int(requests.get("limit","10000000"))
        #ofst = int(requests.get("offset","0"))
        order = requests.get("order","APS")
        timing = bool(requests.get("timing",False))
        api = bool(requests.get("api",False))
        
        extraArgs = ""
        
        
        if timing:
            extraArgs += "&timing=1"
        if lim < 100000:
            extraArgs += "&amp;limit=" + str(lim)
            
            
        reverseSort = True
        if len(order) == 0:
            order = "APS"
        if order[0] == "-":
            order = order[1:]
            reverseSort = False
        if order == "Latest Battle":
            order = "LastUpload"
        elif order == "Competitor":
            order = "Name"
        elif order == "Vote":
            order = "VoteScore"
            
        parsing = time.time() - starttime
        #rumble = global_dict.get(game,None)
        #if rumble is None:
        rumble = memcache.get(game)
        if rumble is None:
            rumble = structures.Rumble.get_by_key_name(game)
            if rumble is None:
                self.response.out.write("RUMBLE NOT FOUND")
                return
            else:
                #global_dict[game]=rumble
                memcache.set(game,rumble)
        #else:
            #global_dict[game] = rumble
        
        #flagmap = global_dict.get(structures.default_flag_map,None)
        #if flagmap is None:
        flagmap = memcache.get(structures.default_flag_map)
        if flagmap is None:
            flagmapholder = structures.FlagMap.get_by_key_name(structures.default_flag_map)
            if flagmapholder is None:
                flagmap = zlib.compress(marshal.dumps({}))
            else:
                flagmap = flagmapholder.InternalMap
                memcache.set(structures.default_flag_map,flagmap)
                #global_dict[structures.default_flag_map] = flagmap
           # else:
              #  global_dict[structures.default_flag_map] = flagmap
        
        try:
            flagmap = pickle.loads(zlib.decompress(flagmap))
        except:
            flagmap = marshal.loads(zlib.decompress(flagmap))
        
        
        try:
        #print "try json"
            botsdict = pickle.loads(zlib.decompress(rumble.ParticipantsScores))
            bots = botsdict.values()
#       try:        
#           self.response.out.write( " json worked")
        except:
           
#               self.response.out.write( "\ntry pickle")
                scoresdicts = marshal.loads(zlib.decompress(rumble.ParticipantsScores))
                scoreslist = [structures.LiteBot() for _ in scoresdicts]
                for s,d in zip(scoreslist,scoresdicts):
                    s.__dict__.update(d)
                #r = {s.Name:s for s in scoreslist}
                bots = scoreslist

#               print " pickle worked"
            
               
            
        retrievetime = time.time() - starttime - parsing
        #newbots = []
        for b in bots:
            b.PWIN = 50.0*float(b.PL)/b.Pairings + 50.0
            
            if b.VoteScore is None:
                b.VoteScore = 0
            if b.ANPP is None:
                b.ANPP = 0
            package = string.split(b.Name,".")[0]
            if package in flagmap:
                b.Flag = flagmap[package]
            else:
                b.Flag = "NONE"
            
        
        get_key = attrgetter(order)
        bots.sort( key=lambda b: get_key(b), reverse=reverseSort)
        
        if api:
            headings = ["\"name\"",
                        "\"flag\"",
                        "\"rank\"",
                        "\"APS\"",
                        "\"PWIN\"",
                        "\"ANPP\"",
                        "\"vote\"",
                        "\"survival\"",
                        "\"pairings\"",
                        "\"battles\"",
                        "\"latest\""]
            escapes = ["\"","\"","","","","","","","","","\""]
            outs = ["[\n"]
            count = 0
            for bot in bots:
                count += 1
                if count > lim:
                    break
                
                
                cells = [
                bot.Name,bot.Flag,count,
                round(100.0*bot.APS)*0.01,
                round(100.0*bot.PWIN)*0.01,
                round(100.0*bot.ANPP)*0.01,
                round(100.0*bot.VoteScore)*0.01,
                round(100.0*bot.Survival)*0.01,
                bot.Pairings,bot.Battles,bot.LastUpload]
                
                outs.append("{")
                for i in range(len(cells)):
                    outs.append(headings[i])
                    outs.append(":")
                    outs.append(escapes[i])
                    outs.append(str(cells[i]))
                    outs.append(escapes[i])
                    outs.append(",")
                outs[-1] = "},\n"
            outs[-1] = ("}\n]")
            self.response.out.write(''.join(outs))

                
        else:

        
            sorttime = time.time() - parsing - retrievetime - starttime
            
            if  order == "LastUpload":
                order = "Latest Battle"
            elif order == "Name":
                order = "Competitor"
            elif order == "VoteScore":
                order = "Vote"
            out = []
            
            gameTitle = "RANKINGS - " + string.upper(game) + " WITH " + str(len(bots)) + " BOTS"
            out.append(structures.html_header % (game,gameTitle))
            
            pairVals = [b.Pairings for b in bots]
            if max(pairVals) == min(pairVals) == (len(bots)-1):
                out.append("<big>Rankings Stable</big>")
            else:
                out.append("<big>Rankings Not Stable</big>")
            out.append("\n<table>\n<tr>");
            
            headings = ["","Flag","Competitor","APS","PWIN","ANPP","Vote","Survival","Pairings","Battles","Latest Battle"]
            for heading in headings:
                sortedBy = order == heading
                if order == heading and reverseSort:
                    heading = "-" + heading
                orderl = []
                orderl.append("<a href=\"Rankings?game=")
                orderl.append(game)
                orderl.append("&amp;order=")
                orderl.append(heading.replace(" ","%20"))
                orderl.append(extraArgs)
                orderl.append("\">")
                orderl.append(heading)
                orderl.append("</a>")
                orderHref = ''.join(orderl)
                if sortedBy:
                    out.append( "\n<th class=\"sortedby\">" + orderHref + "</th>")
                else:
                    out.append( "\n<th>" + orderHref + "</th>")
            out.append("\n</tr>")
            rank = 1
            for bot in bots:
                if rank > lim:
                    break
                    
                botName=bot.Name
                bnh = []
                bnh.append("<a href=\"BotDetails?game=")
                bnh.append(game)
                bnh.append("&amp;name=")
                bnh.append(botName.replace(" ","%20"))
                bnh.append(extraArgs)
                bnh.append("\" >")
                bnh.append(botName)
                bnh.append("</a>")
                botNameHref = ''.join(bnh) #"<a href=BotDetails?game="+game+"&name=" + botName.replace(" ","%20")+extraArgs+">"+botName+"</a>"
                
                ft = []
                ft.append("<img id='flag' src=\"/flags/")
                ft.append(bot.Flag)
                ft.append(".gif\">")
                flagtag = ''.join(ft)
                
                cells = [rank,flagtag,botNameHref,
                    round(100.0*bot.APS)*0.01,
                    round(100.0*bot.PWIN)*0.01,
                    round(100.0*bot.ANPP)*0.01,
                    round(100.0*bot.VoteScore)*0.01,
                    round(100.0*bot.Survival)*0.01,
                    bot.Pairings,bot.Battles,bot.LastUpload]
                    
                out.append("\n<tr>")
                for cell in cells:
                    out.append( "\n<td>")
                    out.append(str(cell))
                    out.append("</td>")
                out.append("\n</tr>")
                del bot.PWIN
                rank += 1
                
            out.append( "</table>")
            htmltime = time.time() - parsing - retrievetime - sorttime - starttime
            
            elapsed = time.time() - starttime
            if timing:
                out.append("\n<br> Page served in " + str(int(round(elapsed*1000))) + "ms. ")# + str(len(missingHashes)) + " bots retrieved from datastore.")
                out.append("\n<br> parsing: " + str(int(round(parsing*1000))) )
                out.append("\n<br> retrieve: " + str(int(round(retrievetime*1000))) )
                out.append("\n<br> sort: " + str(int(round(sorttime*1000))) )
                out.append("\n<br> html generation: " + str(int(round(htmltime*1000))) )
            out.append( "</body></html>")
            
            outstr = ''.join(out)
                
            self.response.out.write(outstr)
Пример #3
0
class HandleQueuedResults(webapp.RequestHandler):
    def post(self):
        global global_dict
        #global_dict = {}
        global global_sync
        global locks
        global last_write
        #global sync_lock

        #        starttime = time.time()
        results = json.loads(self.request.body)

        rumble = results.get("game", "ERROR")

        syncname = str(
            bool(results.get("melee") == "YES")) + "|" + structures.sync
        if syncname not in locks:
            locks[syncname] = threading.Lock()
        sync_lock = locks[syncname]

        global_sync[syncname] = global_sync.get(syncname, {})
        botsync = global_sync[syncname]

        bota = results.get("fname")
        botb = results.get("sname")
        #bota = rreplace(bota,"_"," ",1)
        #botb = rreplace(botb,"_"," ",1)
        logging.debug("Bots : " + bota + " vs. " + botb)

        bd = [[bota, rumble], [botb, rumble]]

        botHashes = [string.join(a, "|").encode('ascii') for a in bd]

        memget = [rumble]
        memget.extend(botHashes)  #botHashes.append(rumble)
        memdict = memcache.get_multi(memget)

        game = memdict.get(rumble, None)
        game_future = None
        if game is None:
            #game = structures.Rumble.get_by_key_name(rumble)
            game_future = db.get_async(db.Key.from_path('Rumble', rumble))

        newBot = False

        bots = [memdict.get(h, None) for h in botHashes]

        pairingsarray = [[], []]
        botFutures = [None, None]
        for i in [0, 1]:
            if bots[i] is None or bots[i].PairingsList is None:
                botFutures[i] = db.get_async(
                    db.Key.from_path('BotEntry', botHashes[i]))

        for i in [0, 1]:
            if botFutures[i] is not None:
                modelbot = botFutures[i].get_result()
                if modelbot is not None:
                    bots[i] = structures.CachedBotEntry(modelbot)
                    #logging.debug("retrieved from database")

        for i in [0, 1]:
            if bots[i] is None:
                modelbot = structures.BotEntry(key_name=botHashes[i],
                                               Name=bd[i][0],
                                               Battles=0,
                                               Pairings=0,
                                               APS=0.0,
                                               Survival=0.0,
                                               PL=0,
                                               Rumble=rumble,
                                               Active=False,
                                               PairingsList=zlib.compress(
                                                   pickle.dumps([]), 1))
                bots[i] = structures.CachedBotEntry(modelbot)
                newBot = True
            if isinstance(bots[i], structures.BotEntry):
                bots[i] = structures.CachedBotEntry(bots[i])

            try:
                pairingsarray[i] = pickle.loads(
                    zlib.decompress(bots[i].PairingsList))
                bots[i].PairingsList = None
            except:
                try:
                    pairsDicts = marshal.loads(
                        zlib.decompress(bots[i].PairingsList))

                    pairingsarray[i] = [
                        structures.ScoreSet() for _ in pairsDicts
                    ]
                    for s, d in zip(pairingsarray[i], pairsDicts):
                        s.__dict__.update(d)
                    bots[i].PairingsList = None
                except:
                    pairingsarray[i] = []

        if game_future is not None:
            game = game_future.get_result()

        if game is None:
            game = structures.Rumble(key_name=rumble,
                                     Name=rumble,
                                     Rounds=int(results["rounds"]),
                                     Field=results["field"],
                                     Melee=bool(results["melee"] == "YES"),
                                     Teams=bool(results["teams"] == "YES"),
                                     TotalUploads=0,
                                     MeleeSize=10,
                                     ParticipantsScores=db.Blob(
                                         zlib.compress(pickle.dumps([]))))
            self.response.out.write("CREATED NEW GAME TYPE " + rumble + "\n")

            logging.info("Created new game type: " + rumble)
        else:
            field = game.Field == results["field"]
            rounds = (game.Rounds == int(results["rounds"]))
            teams = game.Teams == bool(results["teams"] == "YES")
            melee = game.Melee == bool(results["melee"] == "YES")
            allowed = field and rounds and teams and melee
            if not allowed:
                errstr = "OK. ERROR. Incorrect " + rumble + " config: "
                errorReasons = []
                if not field:
                    errorReasons.append("field size ")
                if not rounds:
                    errorReasons.append("number of rounds ")
                if not teams:
                    errorReasons.append("teams ")
                if not melee:
                    errorReasons.append("melee ")
                logging.error(errstr + string.join(errorReasons, ", ") +
                              "  User: "******"user"])

                return
        scores = None

        try:
            scores = pickle.loads(zlib.decompress(game.ParticipantsScores))
            game.ParticipantsScores = None
            if len(scores) == 0:
                scores = {}
        except:
            scoresdicts = marshal.loads(
                zlib.decompress(game.ParticipantsScores))
            game.ParticipantsScores = None
            scoreslist = [structures.LiteBot(loadDict=d) for d in scoresdicts]
            #for s,d in zip(scoreslist,scoresdicts):
            #    s.__dict__.update(d)
            scores = {s.Name: s for s in scoreslist}
            if len(scores) == 0:
                scores = {}

            #logging.debug("uncompressed scores: " + str(len(s)) + "   compressed: " + str(a))

        for i in [0, 1]:

            if not bots[i].Active or bots[i].Name not in scores:
                bots[i].Active = True
                scores[bots[i].Name] = structures.LiteBot(bots[i])
                newBot = True
                self.response.out.write("Added " + bd[i][0] + " to " + rumble +
                                        "\n")
                logging.info("added new bot!")

        #retrievetime = time.time() - starttime

        scorea = float(results["fscore"])
        scoreb = float(results["sscore"])

        if scorea + scoreb > 0:
            APSa = 100 * scorea / (scorea + scoreb)
        else:
            APSa = 50  #register a 0/0 as 50%
        #APSb = 100 - APSa

        survivala = float(results["fsurvival"])
        survivalb = float(results["ssurvival"])

        survivala = 100.0 * survivala / game.Rounds
        survivalb = 100.0 * survivalb / game.Rounds

        for b, pairings in zip(bots, pairingsarray):

            #b.PairingsList = zlib.compress(marshal.dumps([s.__dict__ for s in pairings]),1)

            if len(pairings) > 0:
                removes = []
                for p in pairings:
                    try:
                        p.APS = float(p.APS)
                        p.Survival = float(p.Survival)
                        p.Battles = int(p.Battles)
                    except:
                        removes.append(pairings.index(p))
                        continue

                removes.sort(reverse=True)
                for i in removes:
                    pairings.pop(i)

        apair = None
        for p in pairingsarray[0]:
            if p.Name == botb:
                apair = p
        if apair is None:
            apair = structures.ScoreSet(name=botb)
            pairingsarray[0].append(apair)

        bpair = None
        for p in pairingsarray[1]:
            if p.Name == bota:
                bpair = p
        if bpair is None:
            bpair = structures.ScoreSet(name=bota)
            pairingsarray[1].append(bpair)

        #participantsSet = set(game.Participants)

        for b, pairings in zip(bots, pairingsarray):
            i = 0
            while i < len(pairings):
                if pairings[i].Name == b.Name:
                    pairings.pop(i)
                    continue
                if not hasattr(pairings[i], "Alive"):
                    pairings[i].Alive = True

                if pairings[i].Alive and pairings[i].Name not in scores:
                    pairings[i].Alive = False

                i += 1
            #b.Pairings = i

        aBattles = apair.Battles

        #rolling average with a half-life of 10k
        maxPerPair = 10000 / len(bots)
        if aBattles > maxPerPair:
            aBattles = maxPerPair

        #bBattles = bpair.Battles

        inv_ab = 1.0 / (aBattles + 1.0)

        apair.APS *= float(aBattles) * inv_ab
        apair.APS += APSa * inv_ab
        apair.__dict__["Min_APS"] = min(APSa,
                                        apair.__dict__.get("Min_APS", 100))
        #bpair.APS *= float(bBattles)/(bBattles + 1)
        #bpair.APS += APSb/(bBattles+1)
        bpair.APS = 100 - apair.APS
        bpair.__dict__["Min_APS"] = min(100 - APSa,
                                        bpair.__dict__.get("Min_APS", 100))

        apair.Survival *= float(aBattles) * inv_ab
        apair.Survival += survivala * inv_ab

        bpair.Survival *= float(aBattles) * inv_ab
        bpair.Survival += survivalb * inv_ab

        apair.Battles += 1
        bpair.Battles = apair.Battles

        apair.LastUpload = datetime.datetime.now().strftime(
            "%Y-%m-%d %H:%M:%S")
        bpair.LastUpload = apair.LastUpload

        for b, pairings in zip(bots, pairingsarray):
            aps = 0.0
            survival = 0.0
            pl = 0
            battles = 0
            alivePairings = 0
            if len(pairings) > 0:

                for p in pairings:
                    if p.Alive:
                        aps += p.APS
                        survival += p.Survival
                        if p.APS > 50:
                            pl += 1
                        else:
                            pl -= 1

                        battles += p.Battles
                        alivePairings += 1

                aps /= alivePairings
                survival /= alivePairings
                b.APS = aps
                b.Survival = survival
                b.PL = pl
                b.Battles = battles

            b.PairingsList = db.Blob(
                zlib.compress(pickle.dumps(pairings, pickle.HIGHEST_PROTOCOL),
                              1))
            b.LastUpload = apair.LastUpload
            b.Pairings = alivePairings

        game.TotalUploads += 1

        #self.response.out.write("<" + str(bots[0].Battles) + " " + str(bots[1].Battles) + ">")
        game.LastUpload = apair.LastUpload
        game.AvgBattles = game.AvgBattles * 0.99 + 0.005 * (bots[0].Battles +
                                                            bots[1].Battles)
        if game.Uploaders is None:
            uploaders = None
        else:
            uploaders = pickle.loads(zlib.decompress(game.Uploaders))
        if uploaders is None or len(uploaders) == 0:
            uploaders = {}
        uploaderName = results["user"]

        try:
            uploader = uploaders[uploaderName]
            uploader.latest = apair.LastUpload
            uploader.total += 1
        except KeyError:
            uploader = structures.User(name=uploaderName)
            uploaders[uploaderName] = uploader
        game.Uploaders = zlib.compress(pickle.dumps(uploaders, -1), 1)

        for b in bots:
            try:
                bUploaders = b.Uploaders
                if uploaderName not in bUploaders:
                    bUploaders.append(uploaderName)
            except:
                b.__dict__["Uploaders"] = [uploaderName]

        with sync_lock:
            for b in bots:
                key = None
                if isinstance(b, structures.BotEntry):
                    key = b.key().name()
                else:
                    key = b.key_name
                botsync[key] = botsync.get(key, 0) + 1

            minSize = min(10, len(scores) / 2)
            wrote = False

            logging.debug("botsync: " + str(len(botsync)))

            if len(botsync) > minSize:
                syncset = botsync.keys()

                syncbotsDict = memcache.get_multi(syncset)

                syncbots = []
                for sb in syncset:
                    b = syncbotsDict.get(sb, None)

                    if b is None or b.PairingsList is None:
                        syncbotsDict.pop(sb, 1)
                    else:
                        syncbots.append(b)

                    botsync.pop(sb, 1)

                try:
                    thisput = []
                    while len(syncbots) > 0:
                        b = syncbots.pop()

                        key = None
                        if isinstance(b, structures.BotEntry):
                            key = b.key().name()
                        else:
                            key = b.key_name

                        putb = structures.BotEntry(key_name=key)
                        putb.init_from_cache(b)
                        thisput.append(putb)

                    db.put(thisput)

                    logging.info("wrote " + str(len(thisput)) +
                                 " results to database")
                    for b in thisput:
                        s = b.key().name()
                        botsync.pop(s, 1)
                        syncbotsDict.pop(s, 1)
                    wrote = True

                except Exception, e:
                    logging.error('Failed to write data: ' + str(e))
                    #self.response.out.write('Failed to write data: '+ str(e.__class__))

        for b in bots:
            if b.Name in scores:
                lb = scores[b.Name]
                b.ANPP = lb.ANPP
                b.VoteScore = lb.VoteScore
                scores.pop(b.Name, 1)
            scores[b.Name] = structures.LiteBot(b)

        game.ParticipantsScores = db.Blob(
            zlib.compress(pickle.dumps(scores, pickle.HIGHEST_PROTOCOL), 1))
        game.Participants = []

        if game.BatchScoresAccurate:
            game.BatchScoresAccurate = False
            if not newBot:
                game.put()
                wrote = True

        if newBot or wrote:
            game.put()
            #db.put(bots)
            memcache.delete("home")

        botsDict = {rumble: game}
        global_dict[rumble] = game
        for b in bots:
            if isinstance(b, structures.BotEntry):
                b = structures.CachedBotEntry(b)

            key = b.key_name
            botsDict[key] = b
        memcache.set_multi(botsDict)

        # puttime = time.time() - scorestime - retrievetime - starttime
        scoreVals = scores.values()
        maxPairs = len(scoreVals) - 1

        if game.PriorityBattles and (
            (not game.Melee) or
            (random.random() < 0.0222 or bots[0].Pairings != maxPairs
             or bots[1].Pairings != maxPairs
             or min([bots[0].Battles, bots[1].Battles]) == min(
                 [b.Battles for b in scoreVals]))
        ):  # or min(bots, key = lambda b: b.Battles) < game.AvgBattles):
            #do a gradient descent to the lowest battled pairings:
            #1: take the bot of this pair which has less pairings/battles
            #2: find an empty pairing or take a low pairing
            #3: ????
            #4: PROFIT!!!

            priobot = None
            priopairs = None

            #logging.debug("Maxpairs: " + str(maxPairs))

            #let's do a direct search since we already have the data
            #First look for bots missing pairings
            missingPairings = filter(lambda b: b.Pairings != maxPairs,
                                     scoreVals)

            #logging.debug("missingPairings: " + str(len(missingPairings)))
            priobot2 = None

            if len(missingPairings) > 0:

                total = 0
                #weight bots based on how different they are from desired pairings
                weighted = [(abs(maxPairs - b.Pairings), b)
                            for b in missingPairings]

                #select them for battles according to that weight
                for t in weighted:
                    total += t[0]
                running = 0
                point = random.randint(0, total - 1)
                for t in weighted:
                    running += t[0]
                    if running > point:
                        priobot = t[1]
                        break
                #check if we have the selected bot already loaded
                if priobot.Name == bots[0].Name:
                    priobot = bots[0]
                    priopairs = pairingsarray[0]
                elif priobot.Name == bots[1].Name:
                    priobot = bots[1]
                    priopairs = pairingsarray[1]
                else:
                    #if not try to load them from memcache, but only if we need a special battle
                    if priobot.Pairings < maxPairs:
                        bhash = priobot.Name + "|" + rumble
                        fullPrioBot = memcache.get(bhash)
                    else:
                        fullPrioBot = None

                    if fullPrioBot:
                        priopairs = pickle.loads(
                            zlib.decompress(fullPrioBot.PairingsList))
                        logging.info(
                            "memcache lookup shortcut to local search")
                    else:
                        #if they aren't in memcache give them a generic battle
                        priobot2 = random.choice(scoreVals).Name
                        catch = 10
                        while priobot2 == priobot.Name and catch > 0:
                            priobot2 = random.choice(scoreVals).Name
                            catch -= 1
                        if catch == 0:
                            priobot2 = None
                            logging.info("repeatedly found same bot for prio")
                        else:
                            logging.info(
                                "global min search successful for non-paired bot"
                            )

                if priobot != None and priobot2 == None:
                    #create the first battle of a new pairing

                    #cache pairings into dictionary to speed lookups against entire rumble
                    pairsdict = {}
                    for b in priopairs:
                        pairsdict[b.Name] = b

                    #select all unpaired bots
                    possPairs = []
                    for p in scores:
                        if p not in pairsdict and p != priobot.Name:
                            possPairs.append(p)

                    if len(possPairs) > 0:
                        #choose a random new pairing to prevent overlap
                        priobot2 = random.choice(possPairs)
                        logging.info("successful local search for new pair")
                    else:
                        logging.info("unsuccessful local search for new pair")
            else:
                minBattles = 1.1 * min(
                    [b.Battles for b in scoreVals if b.Active])
                possBots = filter(
                    lambda b: b.Battles <= minBattles and b.Active, scoreVals)

                names = [b.Name for b in possBots]
                if bots[1].Name not in names and bots[0].Name not in names:
                    priobot = random.choice(possBots)

                    bhash = priobot.Name + "|" + rumble
                    fullPrioBot = memcache.get(bhash)
                    if fullPrioBot:
                        priopairs = pickle.loads(
                            zlib.decompress(fullPrioBot.PairingsList))
                        logging.info(
                            "memcache lookup shortcut to global search")
                    else:
                        priobot2 = random.choice(scoreVals).Name
                        catch = 10
                        while priobot2 == priobot.Name and catch > 0:
                            priobot2 = random.choice(scoreVals).Name
                            catch -= 1
                        if catch == 0:
                            priobot2 = None
                            logging.info("repeatedly found same bot for prio")
                        else:
                            logging.info(
                                "global min search successful for low-battled bot"
                            )

                elif bots[0].Battles <= bots[1].Battles:
                    priobot = bots[0]
                    priopairs = pairingsarray[0]
                else:
                    priobot = bots[1]
                    priopairs = pairingsarray[1]

            if priobot2 is None and priopairs is not None:

                #sort for lowest battled pairing
                #priopairs = sorted(priopairs, key = lambda score: score.Battles)

                minbat = min([
                    p.Battles for p in priopairs
                    if p.Name in scores and scores[p.Name].Active
                ])
                possPairs = filter(
                    lambda p: p.Battles <= minbat and p.Name != priobot.Name
                    and p.Name in scores and scores[p.Name].Active, priopairs)
                if len(possPairs) < min(50, 0.5 * len(scores)):
                    possPairs = filter(
                        lambda p: p.Battles <= minbat + 1 and p.Name != priobot
                        .Name and p.Name in scores and scores[p.Name].Active,
                        priopairs)
                if len(possPairs) > 0:
                    priobot2 = random.choice(possPairs).Name
                    logging.info(
                        "successful local search for low-battled pair")
                    #choose low battles, but still random - prevents lots of duplicates
                else:
                    logging.info(
                        "unsuccessful local search for low-battled pair")

            if priobot is not None and priobot2 is not None:
                priobots = [priobot.Name, priobot2]
                priobots = [b.replace(' ', '_') for b in priobots]

                prio_string = "[" + string.join(priobots, ",") + "]\n"
                logging.info("adding priority battle: " + prio_string + ", " +
                             rumble)

                rq_name = rumble + "|queue"
                try:
                    rumble_queue = global_dict[rq_name]
                    rumble_queue.append(prio_string)
                except KeyError:
                    logging.info("No queue for rumble " + rumble +
                                 ", adding one!")
                    global_dict[rq_name] = deque()
                    rumble_queue = global_dict[rq_name]
                    rumble_queue.append(prio_string)
            else:
                logging.info("no suitable priority battle found in " + rumble)
                if priobot is None:
                    logging.info("priobot is None")
                else:
                    logging.info("priobot2 is None")
        else:
            logging.info("no priority battle attempted for " + rumble)

    # priotime = time.time() - puttime - scorestime - retrievetime - starttime

        self.response.out.write("\nOK. " + bota + " vs " + botb + " received")
Пример #4
0
    def post(self):
        global global_dict
        #global_dict = {}
        global global_sync
        global locks
        global last_write
        #global sync_lock

        #        starttime = time.time()
        results = json.loads(self.request.body)

        rumble = results.get("game", "ERROR")

        syncname = str(
            bool(results.get("melee") == "YES")) + "|" + structures.sync
        if syncname not in locks:
            locks[syncname] = threading.Lock()
        sync_lock = locks[syncname]

        global_sync[syncname] = global_sync.get(syncname, {})
        botsync = global_sync[syncname]

        bota = results.get("fname")
        botb = results.get("sname")
        #bota = rreplace(bota,"_"," ",1)
        #botb = rreplace(botb,"_"," ",1)
        logging.debug("Bots : " + bota + " vs. " + botb)

        bd = [[bota, rumble], [botb, rumble]]

        botHashes = [string.join(a, "|").encode('ascii') for a in bd]

        memget = [rumble]
        memget.extend(botHashes)  #botHashes.append(rumble)
        memdict = memcache.get_multi(memget)

        game = memdict.get(rumble, None)
        game_future = None
        if game is None:
            #game = structures.Rumble.get_by_key_name(rumble)
            game_future = db.get_async(db.Key.from_path('Rumble', rumble))

        newBot = False

        bots = [memdict.get(h, None) for h in botHashes]

        pairingsarray = [[], []]
        botFutures = [None, None]
        for i in [0, 1]:
            if bots[i] is None or bots[i].PairingsList is None:
                botFutures[i] = db.get_async(
                    db.Key.from_path('BotEntry', botHashes[i]))

        for i in [0, 1]:
            if botFutures[i] is not None:
                modelbot = botFutures[i].get_result()
                if modelbot is not None:
                    bots[i] = structures.CachedBotEntry(modelbot)
                    #logging.debug("retrieved from database")

        for i in [0, 1]:
            if bots[i] is None:
                modelbot = structures.BotEntry(key_name=botHashes[i],
                                               Name=bd[i][0],
                                               Battles=0,
                                               Pairings=0,
                                               APS=0.0,
                                               Survival=0.0,
                                               PL=0,
                                               Rumble=rumble,
                                               Active=False,
                                               PairingsList=zlib.compress(
                                                   pickle.dumps([]), 1))
                bots[i] = structures.CachedBotEntry(modelbot)
                newBot = True
            if isinstance(bots[i], structures.BotEntry):
                bots[i] = structures.CachedBotEntry(bots[i])

            try:
                pairingsarray[i] = pickle.loads(
                    zlib.decompress(bots[i].PairingsList))
                bots[i].PairingsList = None
            except:
                try:
                    pairsDicts = marshal.loads(
                        zlib.decompress(bots[i].PairingsList))

                    pairingsarray[i] = [
                        structures.ScoreSet() for _ in pairsDicts
                    ]
                    for s, d in zip(pairingsarray[i], pairsDicts):
                        s.__dict__.update(d)
                    bots[i].PairingsList = None
                except:
                    pairingsarray[i] = []

        if game_future is not None:
            game = game_future.get_result()

        if game is None:
            game = structures.Rumble(key_name=rumble,
                                     Name=rumble,
                                     Rounds=int(results["rounds"]),
                                     Field=results["field"],
                                     Melee=bool(results["melee"] == "YES"),
                                     Teams=bool(results["teams"] == "YES"),
                                     TotalUploads=0,
                                     MeleeSize=10,
                                     ParticipantsScores=db.Blob(
                                         zlib.compress(pickle.dumps([]))))
            self.response.out.write("CREATED NEW GAME TYPE " + rumble + "\n")

            logging.info("Created new game type: " + rumble)
        else:
            field = game.Field == results["field"]
            rounds = (game.Rounds == int(results["rounds"]))
            teams = game.Teams == bool(results["teams"] == "YES")
            melee = game.Melee == bool(results["melee"] == "YES")
            allowed = field and rounds and teams and melee
            if not allowed:
                errstr = "OK. ERROR. Incorrect " + rumble + " config: "
                errorReasons = []
                if not field:
                    errorReasons.append("field size ")
                if not rounds:
                    errorReasons.append("number of rounds ")
                if not teams:
                    errorReasons.append("teams ")
                if not melee:
                    errorReasons.append("melee ")
                logging.error(errstr + string.join(errorReasons, ", ") +
                              "  User: "******"user"])

                return
        scores = None

        try:
            scores = pickle.loads(zlib.decompress(game.ParticipantsScores))
            game.ParticipantsScores = None
            if len(scores) == 0:
                scores = {}
        except:
            scoresdicts = marshal.loads(
                zlib.decompress(game.ParticipantsScores))
            game.ParticipantsScores = None
            scoreslist = [structures.LiteBot(loadDict=d) for d in scoresdicts]
            #for s,d in zip(scoreslist,scoresdicts):
            #    s.__dict__.update(d)
            scores = {s.Name: s for s in scoreslist}
            if len(scores) == 0:
                scores = {}

            #logging.debug("uncompressed scores: " + str(len(s)) + "   compressed: " + str(a))

        for i in [0, 1]:

            if not bots[i].Active or bots[i].Name not in scores:
                bots[i].Active = True
                scores[bots[i].Name] = structures.LiteBot(bots[i])
                newBot = True
                self.response.out.write("Added " + bd[i][0] + " to " + rumble +
                                        "\n")
                logging.info("added new bot!")

        #retrievetime = time.time() - starttime

        scorea = float(results["fscore"])
        scoreb = float(results["sscore"])

        if scorea + scoreb > 0:
            APSa = 100 * scorea / (scorea + scoreb)
        else:
            APSa = 50  #register a 0/0 as 50%
        #APSb = 100 - APSa

        survivala = float(results["fsurvival"])
        survivalb = float(results["ssurvival"])

        survivala = 100.0 * survivala / game.Rounds
        survivalb = 100.0 * survivalb / game.Rounds

        for b, pairings in zip(bots, pairingsarray):

            #b.PairingsList = zlib.compress(marshal.dumps([s.__dict__ for s in pairings]),1)

            if len(pairings) > 0:
                removes = []
                for p in pairings:
                    try:
                        p.APS = float(p.APS)
                        p.Survival = float(p.Survival)
                        p.Battles = int(p.Battles)
                    except:
                        removes.append(pairings.index(p))
                        continue

                removes.sort(reverse=True)
                for i in removes:
                    pairings.pop(i)

        apair = None
        for p in pairingsarray[0]:
            if p.Name == botb:
                apair = p
        if apair is None:
            apair = structures.ScoreSet(name=botb)
            pairingsarray[0].append(apair)

        bpair = None
        for p in pairingsarray[1]:
            if p.Name == bota:
                bpair = p
        if bpair is None:
            bpair = structures.ScoreSet(name=bota)
            pairingsarray[1].append(bpair)

        #participantsSet = set(game.Participants)

        for b, pairings in zip(bots, pairingsarray):
            i = 0
            while i < len(pairings):
                if pairings[i].Name == b.Name:
                    pairings.pop(i)
                    continue
                if not hasattr(pairings[i], "Alive"):
                    pairings[i].Alive = True

                if pairings[i].Alive and pairings[i].Name not in scores:
                    pairings[i].Alive = False

                i += 1
            #b.Pairings = i

        aBattles = apair.Battles

        #rolling average with a half-life of 10k
        maxPerPair = 10000 / len(bots)
        if aBattles > maxPerPair:
            aBattles = maxPerPair

        #bBattles = bpair.Battles

        inv_ab = 1.0 / (aBattles + 1.0)

        apair.APS *= float(aBattles) * inv_ab
        apair.APS += APSa * inv_ab
        apair.__dict__["Min_APS"] = min(APSa,
                                        apair.__dict__.get("Min_APS", 100))
        #bpair.APS *= float(bBattles)/(bBattles + 1)
        #bpair.APS += APSb/(bBattles+1)
        bpair.APS = 100 - apair.APS
        bpair.__dict__["Min_APS"] = min(100 - APSa,
                                        bpair.__dict__.get("Min_APS", 100))

        apair.Survival *= float(aBattles) * inv_ab
        apair.Survival += survivala * inv_ab

        bpair.Survival *= float(aBattles) * inv_ab
        bpair.Survival += survivalb * inv_ab

        apair.Battles += 1
        bpair.Battles = apair.Battles

        apair.LastUpload = datetime.datetime.now().strftime(
            "%Y-%m-%d %H:%M:%S")
        bpair.LastUpload = apair.LastUpload

        for b, pairings in zip(bots, pairingsarray):
            aps = 0.0
            survival = 0.0
            pl = 0
            battles = 0
            alivePairings = 0
            if len(pairings) > 0:

                for p in pairings:
                    if p.Alive:
                        aps += p.APS
                        survival += p.Survival
                        if p.APS > 50:
                            pl += 1
                        else:
                            pl -= 1

                        battles += p.Battles
                        alivePairings += 1

                aps /= alivePairings
                survival /= alivePairings
                b.APS = aps
                b.Survival = survival
                b.PL = pl
                b.Battles = battles

            b.PairingsList = db.Blob(
                zlib.compress(pickle.dumps(pairings, pickle.HIGHEST_PROTOCOL),
                              1))
            b.LastUpload = apair.LastUpload
            b.Pairings = alivePairings

        game.TotalUploads += 1

        #self.response.out.write("<" + str(bots[0].Battles) + " " + str(bots[1].Battles) + ">")
        game.LastUpload = apair.LastUpload
        game.AvgBattles = game.AvgBattles * 0.99 + 0.005 * (bots[0].Battles +
                                                            bots[1].Battles)
        if game.Uploaders is None:
            uploaders = None
        else:
            uploaders = pickle.loads(zlib.decompress(game.Uploaders))
        if uploaders is None or len(uploaders) == 0:
            uploaders = {}
        uploaderName = results["user"]

        try:
            uploader = uploaders[uploaderName]
            uploader.latest = apair.LastUpload
            uploader.total += 1
        except KeyError:
            uploader = structures.User(name=uploaderName)
            uploaders[uploaderName] = uploader
        game.Uploaders = zlib.compress(pickle.dumps(uploaders, -1), 1)

        for b in bots:
            try:
                bUploaders = b.Uploaders
                if uploaderName not in bUploaders:
                    bUploaders.append(uploaderName)
            except:
                b.__dict__["Uploaders"] = [uploaderName]

        with sync_lock:
            for b in bots:
                key = None
                if isinstance(b, structures.BotEntry):
                    key = b.key().name()
                else:
                    key = b.key_name
                botsync[key] = botsync.get(key, 0) + 1

            minSize = min(10, len(scores) / 2)
            wrote = False

            logging.debug("botsync: " + str(len(botsync)))

            if len(botsync) > minSize:
                syncset = botsync.keys()

                syncbotsDict = memcache.get_multi(syncset)

                syncbots = []
                for sb in syncset:
                    b = syncbotsDict.get(sb, None)

                    if b is None or b.PairingsList is None:
                        syncbotsDict.pop(sb, 1)
                    else:
                        syncbots.append(b)

                    botsync.pop(sb, 1)

                try:
                    thisput = []
                    while len(syncbots) > 0:
                        b = syncbots.pop()

                        key = None
                        if isinstance(b, structures.BotEntry):
                            key = b.key().name()
                        else:
                            key = b.key_name

                        putb = structures.BotEntry(key_name=key)
                        putb.init_from_cache(b)
                        thisput.append(putb)

                    db.put(thisput)

                    logging.info("wrote " + str(len(thisput)) +
                                 " results to database")
                    for b in thisput:
                        s = b.key().name()
                        botsync.pop(s, 1)
                        syncbotsDict.pop(s, 1)
                    wrote = True

                except Exception, e:
                    logging.error('Failed to write data: ' + str(e))
Пример #5
0
    def post(self):
        try:
            #global global_dict
            #global_dict = {}
            starttime = time.time()
            cutoff_date = datetime.datetime.now() + datetime.timedelta(-365)
            cutoff_date_string = cutoff_date.strftime("%Y-%m-%d %H:%M:%S")

            parts = self.request.body.split("&")
            requests = {}

            if parts is not None and parts[0] != "":
                for pair in parts:
                    ab = pair.split('=')
                    requests[ab[0]] = ab[1]

            force = bool(requests.get("force", False))
            write = bool(requests.get("write", False))
            minwrite = bool(requests.get("minwrite", False))

            rpcList = []
            client = memcache.Client()

            q = structures.Rumble.all()
            rumbles = []
            for r in q.run():
                memr = memcache.get(r.Name)
                if memr is not None:
                    r = memr
                if r.BatchScoresAccurate and not force:
                    continue
                rumbles.append(r)

            for r in rumbles:
                scoresdicts = pickle.loads(
                    zlib.decompress(r.ParticipantsScores))
                entries = len(scoresdicts)
                r.__dict__["entries"] = entries
            rumbles.sort(key=lambda r: -r.__dict__["entries"])

            first = True
            for r in rumbles:
                if not first:
                    time.sleep(5)
                    gc.collect()
                    gc.collect(2)
                first = False

                logging.info("mem usage at start of " + r.Name + ": " +
                             str(runtime.memory_usage().current()) + "MB")
                try:
                    scores = pickle.loads(zlib.decompress(
                        r.ParticipantsScores))
                except:
                    scoresdicts = marshal.loads(
                        zlib.decompress(r.ParticipantsScores))
                    scoreslist = [structures.LiteBot() for _ in scoresdicts]
                    for s, d in zip(scoreslist, scoresdicts):
                        s.__dict__.update(d)
                    scores = {s.Name: s for s in scoreslist}

                if len(scores) == 0:
                    continue

                r.ParticipantsScores = None
                #gc.collect()

                particHash = [p + "|" + r.Name for p in scores]

                particSplit = list_split(particHash, 32)
                ppDict = {}
                for l in particSplit:
                    ppDict.update(memcache.get_multi(l))
                    time.sleep(0.1)

                particSplit = None

                bots = [ppDict.get(h, None) for h in particHash]

                botsdict = {}

                missingHashes = []
                missingIndexes = []
                for i in xrange(len(bots)):
                    if bots[i] is None:
                        missingHashes.append(particHash[i])
                        missingIndexes.append(i)

                    elif isinstance(bots[i], structures.BotEntry):
                        bots[i] = structures.CachedBotEntry(bots[i])

                if len(missingHashes) > 0:
                    bmis = structures.BotEntry.get_by_key_name(missingHashes)

                    #lost = False
                    lostList = []

                    for i in xrange(len(missingHashes)):
                        if bmis[i] is not None:
                            cb = structures.CachedBotEntry(bmis[i])
                            bots[missingIndexes[i]] = cb
                            botsdict[missingHashes[i]] = cb

                        else:
                            bots[missingIndexes[i]] = None
                            lostList.append(missingHashes[i])
                            #lost = True

                while len(particHash) > 0:
                    particHash.pop()
                particHash = None

                while len(missingHashes) > 0:
                    missingHashes.pop()
                missingHashes = None

                while len(missingIndexes) > 0:
                    missingIndexes.pop()
                missingIndexes = None

                logging.info("mem usage after loading bots: " +
                             str(runtime.memory_usage().current()) + "MB")

                bots = filter(lambda b: b is not None, bots)

                get_key = attrgetter("APS")
                bots.sort(key=lambda b: get_key(b), reverse=True)

                gc.collect()

                botIndexes = {}
                for i, b in enumerate(bots):
                    b.Name = b.Name.encode('ascii')
                    intern(b.Name)
                    botIndexes[b.Name] = i
                    b.VoteScore = 0.

                botlen = len(bots)
                APSs = numpy.empty([botlen, botlen])
                APSs.fill(numpy.nan)
                totalAlivePairs = 0
                for i, b in enumerate(bots):
                    try:
                        pairings = pickle.loads(zlib.decompress(
                            b.PairingsList))
                    except:
                        pairsDicts = marshal.loads(
                            zlib.decompress(b.PairingsList))

                        pairings = [structures.ScoreSet() for _ in pairsDicts]
                        for s, d in zip(pairings, pairsDicts):
                            s.__dict__.update(d)
                    removes = []
                    alivePairings = 0
                    for q, p in enumerate(pairings):
                        j = botIndexes.get(p.Name, -1)
                        if j != -1:
                            APSs[j, i] = numpy.float64(p.APS)
                            p.Alive = True
                            alivePairings += 1
                        else:
                            removes.append(q)
                    b.Pairings = alivePairings
                    totalAlivePairs += alivePairings
                    removes.reverse()
                    removed = False
                    for q in removes:
                        p = pairings[q]
                        if p.LastUpload < cutoff_date_string:
                            removed = True
                            pairings.pop(q)
                        else:
                            if p.Alive:
                                removed = True
                            p.Alive = False
                    if removed:
                        b.PairingsList = zlib.compress(
                            pickle.dumps(pairings, -1), 1)

                gc.collect()

                APSs += numpy.float64(100) - APSs.transpose()
                APSs *= numpy.float64(0.5)

                numpy.fill_diagonal(APSs, numpy.nan)

                gc.collect()
                logging.info(
                    str(len(bots)) + " bots loaded, total of " +
                    str(totalAlivePairs) + " alive pairings")
                logging.info("mem usage after unzipping pairings: " +
                             str(runtime.memory_usage().current()) + "MB")

                #Vote
                mins = numpy.nanmax(APSs, 1)
                for i, minimum in enumerate(mins):
                    minIndexes = numpy.argwhere(APSs[i, ...] == minimum)
                    ties = len(minIndexes)
                    if ties > 0:
                        increment = 1. / ties
                        for minIndex in minIndexes:
                            bots[minIndex].VoteScore += increment

                #inv_len = 1.0/botlen
                for b in bots:
                    if b.Pairings > 0:
                        b.VoteScore = 100.0 * b.VoteScore / float(b.Pairings)
                    else:
                        b.VoteScore = 0

                #KNN PBI
                half_k = int(math.ceil(math.sqrt(botlen) / 2))
                KNN_PBI = -numpy.ones((botlen, botlen))
                for i in xrange(len(bots)):
                    low_bound = max([0, i - half_k])
                    high_bound = min([botlen - 1, i + half_k])
                    low_high_bound = min([i + 1, high_bound])
                    before = APSs[:, low_bound:i]
                    after = APSs[:, low_high_bound:high_bound]
                    compare = numpy.hstack((before, after))
                    mm = numpy.mean(numpy.ma.masked_array(
                        compare, numpy.isnan(compare)),
                                    axis=1)
                    KNN_PBI[:, i] = APSs[:, i] - mm.filled(numpy.nan)

    #                a[i] = 0
    #               logging.info("mean error of transpose: " + str(numpy.mean(numpy.square(a))))

    #KNN_PBI[KNN_PBI == numpy.nan] = -1

    #logging.info("mem usage after KNNPBI: " + str(runtime.memory_usage().current()) + "MB")
    # Avg Normalised Pairing Percentage

                mins = numpy.nanmin(APSs, 1)
                maxs = numpy.nanmax(APSs, 1)
                inv_ranges = numpy.float64(1.0) / (maxs - mins)
                NPPs = -numpy.ones((botlen, botlen))
                for i in range(botlen):
                    if numpy.isfinite(inv_ranges[i]):
                        NPPs[i, :] = numpy.float64(100) * (
                            APSs[i, :] - mins[i]) * inv_ranges[i]
                    else:
                        NPPs[i, :] = numpy.float64(100)

                #NPPs[NPPs] = -1

                #logging.info("mem usage after ANPP: " + str(runtime.memory_usage().current()) + "MB")

                changedBots = []  #bots with new pairings since last run

                # save to cache
                botsdict = {}

                for i, b in enumerate(bots):
                    #                try:
                    pairings = pickle.loads(zlib.decompress(b.PairingsList))
                    #                except:
                    #                    pairsDicts = marshal.loads(zlib.decompress(b.PairingsList))
                    #
                    #                    pairings = [structures.ScoreSet() for _ in pairsDicts]
                    #                    for s,d in zip(pairings,pairsDicts):
                    #                        s.__dict__.update(d)
                    nppCount = 0
                    totalNPP = 0.0

                    apsCount = 0
                    totalAPS = 0.0

                    aliveCount = 0

                    changed = False
                    for p in pairings:
                        j = botIndexes.get(p.Name, -1)
                        if j != -1:
                            p.Alive = True
                            changePotential = (p.KNNPBI == 0.0 and p.NPP == -1)

                            aliveCount += 1
                            p.KNNPBI = float(KNN_PBI[j, i])
                            p.NPP = float(NPPs[j, i])

                            if not numpy.isnan(APSs[j, i]):
                                p.APS = float(APSs[j, i])
                                totalAPS += p.APS
                                apsCount += 1

                            if numpy.isnan(p.KNNPBI):
                                p.KNNPBI = 0

                            if numpy.isnan(p.NPP):
                                p.NPP = -1
                            else:
                                totalNPP += p.NPP
                                nppCount += 1

                            if changePotential and p.KNNPBI != 0.0 and p.NPP != -1:
                                changed = True
                        else:
                            p.Alive = False
                            p.KNNPBI = 0
                            p.NPP = -1

                    if nppCount > 0:
                        b.ANPP = float(totalNPP / nppCount)
                    else:
                        b.ANPP = -1.0
                    if apsCount > 0:
                        b.APS = float(totalAPS / apsCount)
                    else:
                        b.APS = -1.0

                    b.PairingsList = zlib.compress(pickle.dumps(pairings, -1),
                                                   1)
                    b.Pairings = aliveCount
                    if b.Pairings > 0:
                        botsdict[b.key_name] = b
                    if changed:
                        changedBots.append(b)

                KNN_PBI = None
                APSs = None
                NPPs = None
                logging.info("mem usage after zipping: " +
                             str(runtime.memory_usage().current()) + "MB")

                gc.collect()
                #logging.info("mem usage after gc: " + str(runtime.memory_usage().current()) + "MB")
                if len(botsdict) > 0:
                    splitlist = dict_split(botsdict, 20)
                    logging.info("split bots into " + str(len(splitlist)) +
                                 " sections")

                    for d in splitlist:
                        rpcList.append(client.set_multi_async(d))
                        time.sleep(.5)  #throttle

                    logging.info("wrote " + str(len(botsdict)) +
                                 " bots to memcache")

                botsdict.clear()
                botsdict = None

                scores = {b.Name: structures.LiteBot(b) for b in bots}

                # bots = None
                r.ParticipantsScores = None
                gc.collect()

                r.ParticipantsScores = db.Blob(
                    zlib.compress(
                        pickle.dumps(scores, pickle.HIGHEST_PROTOCOL), 3))
                logging.info("mem usage after participants zipping: " +
                             str(runtime.memory_usage().current()) + "MB")
                #r.ParticipantsScores = zlib.compress(marshal.dumps([scores[s].__dict__ for s in scores]),4)
                scores = None

                if write:
                    writebots = [None] * len(bots)
                    for i, b in enumerate(bots):
                        putb = structures.BotEntry(key_name=b.key_name)
                        putb.init_from_cache(b)
                        writebots[i] = putb
                    write_lists = list_split(writebots, 50)
                    for subset in write_lists:
                        db.put(subset)
                        time.sleep(0.1)  #throttle
                    logging.info("wrote " + str(len(writebots)) +
                                 " bots to database")

                while len(bots) > 0:
                    bots.pop()
                bots = None

                if minwrite:
                    writebots = [None] * len(changedBots)
                    for i, b in enumerate(changedBots):
                        putb = structures.BotEntry(key_name=b.key_name)
                        putb.init_from_cache(b)
                        writebots[i] = putb
                    write_lists = list_split(writebots, 50)
                    for subset in write_lists:
                        db.put(subset)
                        time.sleep(0.1)
                    logging.info("wrote " + str(len(writebots)) +
                                 " changed bots to database")

                while len(changedBots) > 0:
                    changedBots.pop()
                changedBots = None
                gc.collect()

                if write or minwrite:
                    r.BatchScoresAccurate = True

                rpcList.append(client.set_multi_async({r.Name: r}))

                db.put([r])
                #gc.collect()
                r = None
                logging.info("mem usage after write: " +
                             str(runtime.memory_usage().current()) + "MB")

            for rpc in rpcList:
                rpc.get_result()

            elapsed = time.time() - starttime
            logging.info("Success in " + str(round(1000 * elapsed) / 1000) +
                         "s")
            self.response.out.write("Success in " +
                                    str(round(1000 * elapsed)) + "ms")
        except:
            logging.exception('')
            elapsed = time.time() - starttime
            logging.info("Error in " + str(round(1000 * elapsed) / 1000) + "s")
            self.response.out.write("Error in " + str(round(1000 * elapsed)) +
                                    "ms")