From 9ec79a0c28ea3a6f7958188bac04808564ea1f02 Mon Sep 17 00:00:00 2001 From: Ant Zucaro Date: Fri, 20 Jul 2012 21:59:10 -0400 Subject: [PATCH] Don't dock Elo points if the player won. After much debate I've included this enhancement. It prevents losing Elo points if you've won the game. While this makes the algorithm not *true* Elo, it prevents the negative perception in the community. People were turning off their tracking for fear of losing Elo points even if they won, and this hopefully will fix that situation. --- xonstat/models.py | 28 +++++++++++++++++++--------- xonstat/views/submission.py | 24 ++++++++++++------------ 2 files changed, 31 insertions(+), 21 deletions(-) diff --git a/xonstat/models.py b/xonstat/models.py index 05a50ea..e8eb3a3 100644 --- a/xonstat/models.py +++ b/xonstat/models.py @@ -113,8 +113,10 @@ class Game(object): scores = {} alivetimes = {} - for (p,s,a) in session.query(PlayerGameStat.player_id, - PlayerGameStat.score, PlayerGameStat.alivetime).\ + winners = [] + for (p,s,a,r,t) in session.query(PlayerGameStat.player_id, + PlayerGameStat.score, PlayerGameStat.alivetime, + PlayerGameStat.rank, PlayerGameStat.team).\ filter(PlayerGameStat.game_id==self.game_id).\ filter(PlayerGameStat.alivetime > timedelta(seconds=0)).\ filter(PlayerGameStat.player_id > 2).\ @@ -123,6 +125,11 @@ class Game(object): scores[p] = s/float(a.seconds) alivetimes[p] = a.seconds + # winners are either rank 1 or on the winning team + # team games are where the team is set (duh) + if r == 1 or (t == self.winner and t is not None): + winners.append(p) + player_ids = scores.keys() elos = {} @@ -144,7 +151,7 @@ class Game(object): del(scores[pid]) del(alivetimes[pid]) - elos = self.update_elos(session, elos, scores, ELOPARMS) + elos = self.update_elos(session, elos, scores, winners, ELOPARMS) # add the elos to the session for committing for e in elos: @@ -155,7 +162,7 @@ class Game(object): # self.process_elos(session, "dm") - def update_elos(self, session, elos, scores, ep): + def update_elos(self, session, elos, scores, winners, ep): eloadjust = {} for pid in elos.keys(): eloadjust[pid] = 0 @@ -207,13 +214,16 @@ class Game(object): for pid in pids: new_elo = max(float(elos[pid].elo) + eloadjust[pid] * elos[pid].k * ep.global_K / float(len(elos) - 1), ep.floor) - # delta is new minus old - elo_deltas[pid] = new_elo - float(elos[pid].elo) - - log.debug("Player {0}'s Elo going from {1} to {2}.".format(pid, + log.debug("Player {0}'s Elo would be going from {1} to {2}.".format(pid, elos[pid].elo, new_elo)) - elos[pid].elo = new_elo + # winners are not penalized with negative elo + if pid in winners and new_elo < elos[pid].elo: + elo_deltas[pid] = 0.0 + else: + elos[pid].elo = new_elo + elo_deltas[pid] = new_elo - float(elos[pid].elo) + elos[pid].games += 1 self.save_elo_deltas(session, elo_deltas) diff --git a/xonstat/views/submission.py b/xonstat/views/submission.py index 950450f..d584915 100644 --- a/xonstat/views/submission.py +++ b/xonstat/views/submission.py @@ -378,19 +378,19 @@ def create_player_game_stat(session=None, player=None, for (key,value) in player_events.items(): if key == 'n': pgstat.nick = value[:128] - if key == 't': pgstat.team = value - if key == 'rank': pgstat.rank = value + if key == 't': pgstat.team = int(value) + if key == 'rank': pgstat.rank = int(value) if key == 'alivetime': pgstat.alivetime = datetime.timedelta(seconds=int(round(float(value)))) - if key == 'scoreboard-drops': pgstat.drops = value - if key == 'scoreboard-returns': pgstat.returns = value - if key == 'scoreboard-fckills': pgstat.carrier_frags = value - if key == 'scoreboard-pickups': pgstat.pickups = value - if key == 'scoreboard-caps': pgstat.captures = value - if key == 'scoreboard-score': pgstat.score = value - if key == 'scoreboard-deaths': pgstat.deaths = value - if key == 'scoreboard-kills': pgstat.kills = value - if key == 'scoreboard-suicides': pgstat.suicides = value + if key == 'scoreboard-drops': pgstat.drops = int(value) + if key == 'scoreboard-returns': pgstat.returns = int(value) + if key == 'scoreboard-fckills': pgstat.carrier_frags = int(value) + if key == 'scoreboard-pickups': pgstat.pickups = int(value) + if key == 'scoreboard-caps': pgstat.captures = int(value) + if key == 'scoreboard-score': pgstat.score = int(value) + if key == 'scoreboard-deaths': pgstat.deaths = int(value) + if key == 'scoreboard-kills': pgstat.kills = int(value) + if key == 'scoreboard-suicides': pgstat.suicides = int(value) # check to see if we had a name, and if # not use an anonymous handle @@ -405,7 +405,7 @@ def create_player_game_stat(session=None, player=None, # if the player is ranked #1 and it is a team game, set the game's winner # to be the team of that player # FIXME: this is a hack, should be using the 'W' field (not present) - if pgstat.rank == '1' and pgstat.team: + if pgstat.rank == 1 and pgstat.team: game.winner = pgstat.team session.add(game) -- 2.39.2