-
Notifications
You must be signed in to change notification settings - Fork 2
/
ts_ranking.py
executable file
·100 lines (87 loc) · 3.88 KB
/
ts_ranking.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#!/usr/bin/env python3
import argparse
import json
import math
import sys
import trueskill
import utility
def ts_ratings(game_results):
players = {p: trueskill.Rating() for p in
set(p for game in game_results for p in game)}
for gnum, game in enumerate(game_results, start=1):
game = list(game.items())
ratings = [{p[0]: players[p[0]]} for p in game]
ranks = [(p[1],) for p in game]
ratings = trueskill.rate(ratings, ranks)
for group in ratings:
for name, rating in group.items():
players[name] = rating
if gnum % 10000 == 0:
print("\rRated %d games" % (gnum,), end="")
if gnum >= 10000:
print("\r", end="")
print("Rated %d games" % (gnum,))
return players
def main(args=sys.argv[1:]):
parser = argparse.ArgumentParser("Create TrueSkill ratings from game data.")
parser.add_argument("game_files", nargs="+",
help="Json files containing game data.")
parser.add_argument("-d", "--display", type=int, default=40,
help="Limit display of rating to top N (0 for all)")
parser.add_argument("-n", "--num-games", type=int,
help="Limit the number of games used (positive for first, negative for last")
parser.add_argument("--remove-suspect", action="store_true",
help="Filter out suspect games based on workerID.")
parser.add_argument("--no-error", action="store_true",
help="Filter out games that had bot errors.")
parser.add_argument("-o", "--out-file",
help="If specified will write the full ratings to given filename")
parser.add_argument("-t", "--tau", type=float,
help="Set trueskill tau.")
parser.add_argument("--draw-prob", type=float,
help="Set trueskill draw probability.")
config = parser.parse_args(args)
games = utility.load_games(config.game_files)
if config.no_error:
games = utility.filter_error_games(games)
print("Filtered out error games, leaving %d" % (len(games),))
if config.remove_suspect:
start_num = len(games)
games = utility.filter_suspect_games(games)
print("Filtered out %d suspect games, leaving %d" % (
start_num - len(games), len(games)))
game_results = [{"%s (%s)" % (u['username'], u['userID']): int(u['rank'])
for u in g['users']}
for g in games]
if config.num_games:
if config.num_games > 0:
game_results = game_results[:config.num_games]
print("Using first %d games." % (len(game_results),))
else:
game_results = game_results[config.num_games:]
print("Using last %d games." % (len(game_results),))
if config.tau is not None:
trueskill.global_env().tau = config.tau
print("Using tau %g" % (trueskill.global_env().tau,))
if config.draw_prob is not None:
trueskill.global_env().draw_probability = config.draw_prob
print("Using draw probability %g" % (
trueskill.global_env().draw_probability,))
ratings = ts_ratings(game_results)
ratings = sorted(ratings.items(), key=lambda x: -(x[1].mu - (x[1].sigma*3)))
if config.out_file:
with open(config.out_file, 'w') as out:
for rank, (player, rating) in enumerate(ratings, start=1):
score = rating.mu - (rating.sigma * 3)
out.write('%d,%s,%f,%r,%r\n' % (rank, player, score,
rating.mu, rating.sigma))
if config.display > 0:
ratings = ratings[:config.display]
rwidth = math.floor(math.log10(len(ratings))) + 1
pwidth = max(len(r[0]) for r in ratings)
for rank, (player, rating) in enumerate(ratings, start=1):
score = rating.mu - (rating.sigma * 3)
print("%*d: %*s %.2f (%.2f, %.2f)" % (rwidth, rank, pwidth, player,
score, rating.mu, rating.sigma))
if __name__ == "__main__":
main()