]> de.git.xonotic.org Git - xonotic/xonstat.git/commitdiff
Add elo delta tracking.
authorAnt Zucaro <azucaro@gmail.com>
Wed, 20 Jun 2012 14:17:10 +0000 (10:17 -0400)
committerAnt Zucaro <azucaro@gmail.com>
Wed, 20 Jun 2012 14:17:10 +0000 (10:17 -0400)
An elo delta is the amount by which a player's elo goes up
or down per match. This is useful for tracking purposes
and competitions.

The decimal formatting here is a bit hacky, and I don't like it,
but Mako refuses to do a proper format string on a decimal.Decimal.
This is even thought on the interactive command line it works! Argh.

xonstat/models.py
xonstat/templates/scoreboard.mako
xonstat/views/game.py

index 39c65868fc0e92b62c0fa34d80c404d18af2244f..6d3888802810e75ebf268f3a259465fc37283a8c 100644 (file)
@@ -144,7 +144,7 @@ class Game(object):
                 del(scores[pid])
                 del(alivetimes[pid])
 
-        elos = self.update_elos(elos, scores, ELOPARMS)
+        elos = self.update_elos(session, elos, scores, ELOPARMS)
 
         # add the elos to the session for committing
         for e in elos:
@@ -153,7 +153,8 @@ class Game(object):
         if game_type_cd == 'duel':
             self.process_elos(session, "dm")
 
-    def update_elos(self, elos, scores, ep):
+
+    def update_elos(self, session, elos, scores, ep):
         eloadjust = {}
         for pid in elos.keys():
             eloadjust[pid] = 0
@@ -200,12 +201,46 @@ class Game(object):
                 adjustment = scorefactor_real - scorefactor_elo
                 eloadjust[ei.player_id] += adjustment
                 eloadjust[ej.player_id] -= adjustment
+        elo_deltas = {}
         for pid in pids:
-            elos[pid].elo = max(float(elos[pid].elo) + eloadjust[pid] * elos[pid].k * ep.global_K / float(len(elos) - 1), ep.floor)
+            elo_delta = eloadjust[pid] * elos[pid].k * ep.global_K / float(len(elos) - 1)
+
+            if float(elos[pid].elo) + elo_delta < ep.floor:
+                elo_deltas[pid] = elos[pid].elo - ep.floor
+            else:
+                elo_deltas[pid] = elo_delta
+
+            # can't go below the floor
+            elos[pid].elo = max(float(elos[pid].elo) + elo_delta, ep.floor)
             elos[pid].games += 1
+
+        self.save_elo_deltas(session, elo_deltas)
+
         return elos
 
 
+    def save_elo_deltas(self, session, elo_deltas):
+        """
+        Saves the amount by which each player's Elo goes up or down
+        in a given game in the PlayerGameStat row, allowing for scoreboard display.
+
+        elo_deltas is a dictionary such that elo_deltas[player_id] is the elo_delta
+        for that player_id.
+        """
+        pgstats = {}
+        for pgstat in session.query(PlayerGameStat).\
+                filter(PlayerGameStat.game_id == self.game_id).\
+                all():
+                    pgstats[pgstat.player_id] = pgstat
+
+        for pid in elo_deltas.keys():
+            try:
+                pgstats[pid].elo_delta = elo_deltas[pid]
+                session.add(pgstats[pid])
+            except:
+                log.debug("Unable to save Elo delta value for player_id {0}".format(pid))
+
+
 class PlayerGameStat(object):
     def __init__(self, player_game_stat_id=None, create_dt=None):
         self.player_game_stat_id = player_game_stat_id
index 288e271eb2fb3a02610f191e7563cc11089776d4..7b4d940a21768af0926ae18d2754fbb4355c0bf2 100644 (file)
@@ -16,6 +16,11 @@ ${scoreboard_header(game_type_cd, pgstats[0])}
       </td>
     ${scoreboard_row(game_type_cd, pgstat)}
       <td>${pgstat.score}</td>
+      % if pgstat.elo_delta == "0.00":
+          <td></td>
+      % else:
+          <td>${pgstat.elo_delta}</td>
+     % endif
     </tr>
   % endfor
   </tbody>
@@ -32,6 +37,7 @@ ${scoreboard_header(game_type_cd, pgstats[0])}
       <th class="deaths">Deaths</th>
       <th class="suicides">Suicides</th>
       <th class="score">Score</th>
+      <th class="points">Points</th>
     </tr>
     </thead>
 % endif
@@ -46,6 +52,7 @@ ${scoreboard_header(game_type_cd, pgstats[0])}
       <th class="fck" title="Flag Carrier Kill">FCK</th>
       <th class="returns">Returns</th>
       <th class="score">Score</th>
+      <th class="points">Points</th>
     </tr>
     </thead>
 % endif
index 6147c5fed1d44d9b4bac3b16c4e9124e1503dbcb..04774fe283c6e87c40c1c03cec571e924c60bf4a 100644 (file)
@@ -69,6 +69,13 @@ def _game_info_data(request):
                 order_by(PlayerGameStat.score).\
                 all()
 
+        # mako is an absolute bastard when dealing with decimals, so...
+        for pgstat in pgstats:
+            try:
+                pgstat.elo_delta = "{0:+4.2f}".format(float(pgstat.elo_delta))
+            except:
+                pgstat.elo_delta = "0.00"
+
         pwstats = {}
         for (pwstat, pgstat, weapon) in DBSession.query(PlayerWeaponStat, PlayerGameStat, Weapon).\
                 filter(PlayerWeaponStat.game_id == game_id).\