]> git.rm.cloudns.org Git - xonotic/xonstat.git/commitdiff
Don't dock Elo points if the player won.
authorAnt Zucaro <azucaro@gmail.com>
Sat, 21 Jul 2012 01:59:10 +0000 (21:59 -0400)
committerAnt Zucaro <azucaro@gmail.com>
Sat, 21 Jul 2012 01:59:10 +0000 (21:59 -0400)
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
xonstat/views/submission.py

index 05a50ea227292b6d82dafc6bae844af5c6694aa3..e8eb3a371051a7f23e74763ff975c082ff27c604 100644 (file)
@@ -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)
index 950450f1dcc392178307fd72c0bedb2cc0ac5a47..d584915193706fa0bd47e9f1789fd750a1f72e11 100644 (file)
@@ -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)