/
run_trueskill.py
156 lines (129 loc) · 4.88 KB
/
run_trueskill.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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
""" Update trueskill ratings for openings."""
from utils import get_mongo_connection, progress_meter
import trueskill.trueskill as ts
import incremental_scanner
import primitive_util
import utils
def results_to_ranks(results):
sorted_results = sorted(results)
return [sorted_results.index(r) for r in results]
class PrimitiveSkillInfo(primitive_util.PrimitiveConversion):
def to_primitive_object(self):
return {'mu': float(self.mu),
'sigma': float(self.sigma),
'gamma': float(self.gamma),
'floor': float(self.floor),
'ceil': float(self.ceil)}
class DbBackedSkillTable(ts.SkillTable):
def __init__(self, coll):
ts.SkillTable.__init__(self, self._db_backed_missing_func)
self.coll = coll
self.skill_infos = {}
def _db_backed_missing_func(self, name):
if name in self.skill_infos:
return self.skill_infos[name]
db_data = self.coll.find_one({'_id': name})
skill_info = PrimitiveSkillInfo()
if db_data:
skill_info.mu = db_data['mu']
skill_info.sigma = db_data['sigma']
skill_info.gamma = db_data['gamma']
else:
skill_info.sigma = 25.0/3
if name.startswith('open:'):
skill_info.gamma = 0.0001
skill_info.mu = 0.
else:
skill_info.gamma = 0.
skill_info.mu = 25.
self.skill_infos[name] = skill_info
return self.skill_infos[name]
def add_uncertainty(self, strength, skip_openings=False):
for key, value in self.skill_infos.iteritems():
if not (skip_openings and key.startswith('open:')):
value.sigma = (value.sigma*(1-strength)) + (25./3*strength)
value.floor = value.mu - 3*value.sigma
value.ceil = value.mu + 3*value.sigma
def save(self):
for key, val in self.skill_infos.iteritems():
utils.write_object_to_db(val, self.coll, key)
def setup_openings_collection(coll):
coll.ensure_index('_id')
coll.ensure_index('mu')
coll.ensure_index('floor')
coll.ensure_index('ceil')
def update_skills_for_game(game, opening_skill_table,
player_skill_table
):
teams = []
results = []
openings = []
dups = False
for deck in game['decks']:
if len(deck['turns']) >= 2:
opening = deck['turns'][0].get('buys', []) + \
deck['turns'][1].get('buys', [])
else:
opening = ['resign']
dups = True
opening.sort()
open_name = 'open:' + '+'.join(opening)
if open_name in openings:
dups = True
openings.append(open_name)
nturns = len(deck['turns'])
if deck['resigned']:
vp = -1000
else:
vp = deck['points']
results.append((-vp, nturns))
player_name = deck['name'][:80]
teams.append([open_name, player_name])
ranks = results_to_ranks(results)
if not dups:
team_results = [
(team, [0.5, 0.5], rank)
for team, rank in zip(teams, ranks)
]
ts.update_trueskill_team(team_results, opening_skill_table)
player_results = [
([team[1]], [1.0], rank)
for team, rank in zip(teams, ranks)
]
ts.update_trueskill_team(player_results, player_skill_table)
def run_trueskill_openings():
con = get_mongo_connection()
db = con.test
games = db.games
collection = db.trueskill_openings_dev
player_collection = db.trueskill_players_dev
## if we want to start over:
#db.scanner.remove({'_id': 'trueskill'})
#player_collection.remove()
#collection.remove()
setup_openings_collection(collection)
setup_openings_collection(player_collection)
opening_skill_table = DbBackedSkillTable(collection)
player_skill_table = DbBackedSkillTable(player_collection)
args = utils.incremental_max_parser().parse_args()
scanner = incremental_scanner.IncrementalScanner('trueskill_dev', db)
if not args.incremental:
scanner.reset()
collection.drop()
for ind, game in enumerate(
progress_meter(scanner.scan(db.games, {}), 100)):
if len(game['decks']) >= 2 and len(game['decks'][1]['turns']) >= 2:
update_skills_for_game(game, opening_skill_table, player_skill_table)
if ind == args.max_games:
break
if ind % 15000 == 0:
player_skill_table.save()
player_skill_table.add_uncertainty(0.01)
opening_skill_table.save()
opening_skill_table.add_uncertainty(0.01, skip_openings=True)
scanner.save()
print scanner.status_msg()
def main():
run_trueskill_openings()
if __name__ == '__main__':
main()