From 1de9b97a5d8cf2ba4ed4078baca972e400b73eb3 Mon Sep 17 00:00:00 2001 From: Yannik Schmidt Date: Sat, 2 Nov 2019 11:21:46 +0100 Subject: [PATCH] expand api --- StorrageBackend.py | 116 ++++++++++++++++++++++++++++++--------------- httpAPI.py | 30 ++++++++---- 2 files changed, 99 insertions(+), 47 deletions(-) diff --git a/StorrageBackend.py b/StorrageBackend.py index 7b54711..514271c 100644 --- a/StorrageBackend.py +++ b/StorrageBackend.py @@ -35,6 +35,8 @@ def sync_from_database(players): p.rating = known_players[p].rating if type(players) == dict: players[p] = p.rating + if not p.name or p.name == "PLACEHOLDER": + p.name = known_players[p].name else: lastUpdate = datetime.now() known_players.update(\ @@ -106,27 +108,11 @@ def save_psql(): ###################### Python API ########################### ############################################################# -def getBalanceForPlayers(players, buddies=None): - if not players: - return "" - StorrageBackend.sync_from_database(players) - for p in players: - print(p, p.rating) - arr = sorted(players, key=lambda x: x.rating.mu, reverse=True) - ret="" - i = 0 - while i < len(arr): - ret += "{}|{},".format(players[i].name,(i%2)+2) - i += 1 - return ret - def getPlayer(pid, name="NOTFOUND"): - return known_player[pid] + return known_player[pid] -def fuzzy_find_player(name): - return "Not Implemented" - -def findPlayer(name): +def searchPlayerByName(name): + '''Find a player by his name''' global player_ranks ret = "" @@ -146,22 +132,71 @@ def findPlayer(name): playerRankTupel = [] for p in players: try: - playerRankTupel += [(p, player_ranks[p])] + playerRankTupel += [(p.steamid, p.name, p.rating, player_ranks[p])] except KeyError: - playerRankTupel += [(p, "N/A")] + noRankExplanation = "inactive" + if p.games < 10: + noRankExplanation = "not enough games" + playerRankTupel += [(p.steamid, p.name, p.rating, noRankExplanation)] finally: TS.unlock() return playerRankTupel +def getPlayerRank(playerID): + '''Get a players rank''' -def get_player_rank(p): - global player_ranks - try: - return str(player_ranks[p]) - except KeyError: - return "N/A" + global player_ranks + try: + return str(player_ranks[playerID]) + except KeyError: + return "N/A" + +def getBalancedTeams(players, buddies=None, teamCount=2): + '''Balance a number of players into teams''' + + if teamCount != 2: + raise NotImplementedError("Only supporting balancing into two teams currently") + if not players: + return ValueError("Input contains no players") + + if type(players[0]) == str: + players = [ Player.DummyPlayer(playerID) for playerID in players] + + sync_from_database(players) + + arr = sorted(players, key=lambda x: x.rating.mu, reverse=True) + ret="" + i = 0 + while i < len(arr): + ret += "{}|{},".format(players[i].name,(i%2)+2) + i += 1 + return ret + +def qualityForTeams(teamArray): + '''Get quality for number of teams with players''' + + if not teamArray or len(teamArray) < 2 or not teamArray[0]: + raise ValueError("Team Array must be more than one team with more than one player each") + + if type(teamArray[0][0]) == str: + teamArray = [ [ Player.DummyPlayer(playerID) for playerID in team ] for team in teamArray ] + + for team in teamArray: + print(team[0].steamid) + sync_from_database(team) + + teamAsRatings = [ [ player.rating for player in team ] for team in teamArray ] + teamAsNames = [ [ player.name for player in team ] for team in teamArray ] + + # TODO: implement for !=2 teams # + if len(teamArray) != 2: + raise NotImplementedError("Quality is only supported for exactly two teams") + + return qualityForRatings(teamAsRatings[0], teamAsRatings[1], teamAsNames[0], teamAsNames[1]) + +def qualityForRatings(team1, team2, names1 = [""], names2 = [""]): + '''Get Quality for two arrays containing TrueSkill.Rating objects''' -def quality(team1, team2, names1 = [""], names2 = [""]): mu1 = sum(r.mu for r in team1) mu2 = sum(r.mu for r in team2) mu_tot = mu1 + mu2 @@ -169,34 +204,31 @@ def quality(team1, team2, names1 = [""], names2 = [""]): sig2 = sum(r.sigma for r in team2) sigtot = sig1 + sig2 - names1 = list(map(lambda x: str(x.name), names1)) - names2 = list(map(lambda x: str(x.name), names2)) + print(team1, team2) diff = abs(mu1 - mu2) percent = 50 + diff/mu_tot*100 + if percent > 100: percent = 100 if mu1 > mu2: - string = "{} win at {:.2f}% - {:.2f} to {:.2f} Uncertainty: {:.2f}%".format(\ - ",".join(names1), \ - percent, mu1, mu2, sigtot/diff*100) + string = "{} win at {:.2f}% - {:.2f} to {:.2f}".format(names1, percent, mu1, mu2 ) else: - string = "{} win at {:.2f}% - {:.2f} to {:.2f} Uncertainty: {:.2f}%".format(\ - ",".join(names2), \ - percent, mu2, mu1, sigtot/diff*100) + string = "{} win at {:.2f}% - {:.2f} to {:.2f}".format(names2, percent, mu2, mu1 ) return string def getRankListLength(revalidateRanks=False): - global playerRankList + '''Get the total number of entries in the ranking''' + global playerRankList updatePlayerRanks(revalidateRanks) - return len(playerRankList) def getRankRange(start, end, revalidateRanks=False): '''Returns a list of player, optionally flushing the ranks-cache first''' + global playerRankList print(start,end) @@ -206,9 +238,15 @@ def getRankRange(start, end, revalidateRanks=False): return [] return playerRankList[start:end] -def hasChanged(time): +def rankHasChanged(time): '''Indicates to a http-querier if the availiable data has changed''' + if last_rank_update > time: return "True" else: return "False" + +def debugInformation(): + '''Dump a string of debugging information (this may take some times)''' + + return [ "{} {} {}".format(p.steamid, p.name, p.rating) for p in known_players.values() ] diff --git a/httpAPI.py b/httpAPI.py index 41ae569..2c6aeb6 100644 --- a/httpAPI.py +++ b/httpAPI.py @@ -11,9 +11,14 @@ def invalidParameters(*args): ######################################################## +@app.route('/dumpdebug') +def dumpDebug(): + return "
".join(SB.debugInformation()) + @app.route('/getplayer') def getPlayer(): - raise NotImplementedError() + playerName = flask.request.args.get("name") + return str(SB.searchPlayerByName(playerName)) @app.route('/getmaxentries') def getMaxEntries(): @@ -32,14 +37,23 @@ def getRankRange(): players = SB.getRankRange(start, end) return "\n".join([p.serialize() for p in players]) -@app.route('/findplayer') -def findPlayer(): - string = flask.request.args.get("string") - players = SB.findPlayer(string) - return "|".join([pt[0].serialize() + "," + str(pt[1]) for pt in players]) - @app.route('/haschanged') def hasChanged(): string = flask.request.args.get("time") # TODO get time with timezone - return SB.hasChanged(localizedTime) + return SB.rankHasChanged(localizedTime) + +@app.route('/getbalancedteams') +def getBalancedTeams(): + players = flask.request.args.get("players").split(",") + return SB.getBalancedTeams(players) + +@app.route('/quality') +def quality(): + '''Get a game quality estimate for two or more given teams''' + string = flask.request.args.get("playerswithteams") + teams = string.split("|") + if len(teams) < 2: + flask.abort("Invalid input string: {}".format(string)) + teams = [ x.split(",") for x in teams ] + return SB.qualityForTeams(teams)