return k\r
\r
\r
-# For team games where multiple scores and elos are at play, the elos\r
-# must be adjusted according to their strength relative to the player\r
-# in the next-lowest scoreboard position.\r
-def update(elos, ep):\r
- for x in elos:\r
- if x.elo == None:\r
- x.elo = ep.initial\r
- x.eloadjust = 0\r
- if len(elos) < 2:\r
- return elos\r
- for i in xrange(0, len(elos)):\r
- ei = elos[i]\r
- for j in xrange(i+1, len(elos)):\r
- ej = elos[j]\r
- si = ei.score\r
- sj = ej.score\r
-\r
- # normalize scores\r
- ofs = min(0, si, sj)\r
- si -= ofs\r
- sj -= ofs\r
- if si + sj == 0:\r
- si, sj = 1, 1 # a draw\r
-\r
- # real score factor\r
- scorefactor_real = si / float(si + sj)\r
-\r
- # estimated score factor by elo\r
- elodiff = min(ep.maxlogdistance, max(-ep.maxlogdistance, (ei.elo - ej.elo) * ep.logdistancefactor))\r
- scorefactor_elo = 1 / (1 + math.exp(-elodiff))\r
-\r
- # how much adjustment is good?\r
- # scorefactor(elodiff) = 1 / (1 + e^(-elodiff * logdistancefactor))\r
- # elodiff(scorefactor) = -ln(1/scorefactor - 1) / logdistancefactor\r
- # elodiff'(scorefactor) = 1 / ((scorefactor) (1 - scorefactor) logdistancefactor)\r
- # elodiff'(scorefactor) >= 4 / logdistancefactor\r
-\r
- # adjust'(scorefactor) = K1 + K2\r
-\r
- # so we want:\r
- # K1 + K2 <= 4 / logdistancefactor <= elodiff'(scorefactor)\r
- # as we then don't overcompensate\r
-\r
- adjustment = scorefactor_real - scorefactor_elo\r
- ei.eloadjust += adjustment\r
- ej.eloadjust -= adjustment\r
- for x in elos:\r
- x.elo = max(x.elo + x.eloadjust * x.k * ep.global_K / float(len(elos) - 1), ep.floor)\r
- x.games += 1\r
- return elos\r
-\r
-\r
# parameters for K reduction\r
# this may be touched even if the DB already exists\r
KREDUCTION = KReduction(600, 120, 0.5, 0, 32, 0.2)\r
# only global_K may be touched even if the DB already exists\r
# we start at K=200, and fall to K=40 over the first 20 games\r
ELOPARMS = EloParms(global_K = 200)\r
-\r
filter(PlayerGameStat.alivetime > timedelta(seconds=0)).\
filter(PlayerGameStat.player_id > 2).\
all():
- scores[p] = s
+ # scores are per second
+ scores[p] = s/float(a.seconds)
alivetimes[p] = a.seconds
player_ids = scores.keys()
for e in elos:
session.add(elos[e])
- # TODO: duels are also logged as DM for elo purposes
+ if game_type_cd == 'duel':
+ self.process_elos(session, "dm")
def update_elos(self, elos, scores, ep):
eloadjust = {}
scorefactor_real = si / float(si + sj)
# estimated score factor by elo
- elodiff = min(ep.maxlogdistance, max(-ep.maxlogdistance, (ei.elo - ej.elo) * ep.logdistancefactor))
+ elodiff = min(ep.maxlogdistance, max(-ep.maxlogdistance,
+ (float(ei.elo) - float(ej.elo)) * ep.logdistancefactor))
scorefactor_elo = 1 / (1 + math.exp(-elodiff))
# how much adjustment is good?
adjustment = scorefactor_real - scorefactor_elo
eloadjust[ei.player_id] += adjustment
- eloadjust[ei.player_id] -= adjustment
+ eloadjust[ej.player_id] -= adjustment
+ log.debug("elo adjustment values:")
+ log.debug(eloadjust)
for pid in pids:
- elos[pid].elo = max(elos[pid].elo + eloadjust[pid] * elos[pid].k * ep.global_K / float(len(elos) - 1), ep.floor)
+ elos[pid].elo = max(float(elos[pid].elo) + eloadjust[pid] * elos[pid].k * ep.global_K / float(len(elos) - 1), ep.floor)
elos[pid].games += 1
return elos
class PlayerElo(object):
def __init__(self, player_id=None, game_type_cd=None):
+
self.player_id = player_id
self.game_type_cd = game_type_cd
- self.elo = 0
- self.k = 0.0
self.score = 0
self.games = 0
+ self.elo = ELOPARMS.initial
def __repr__(self):
- return "<PlayerElo(%s, %s, %s)>" % (self.player_id, self.game_type_cd,
- self.elo)
+ return "<PlayerElo(pid=%s, gametype=%s, elo=%s)>" % \
+ (self.player_id, self.game_type_cd, self.elo)
def initialize_db(engine=None):