@@ -63,6 +63,35 @@ def calculate_round_weight_exponential(round_num: int, total_rounds: int, alpha:
6363 return raw_weight * norm_factor
6464
6565
66+ def get_scores (stats : dict ) -> dict [str , float ]:
67+ valid_submits = sum (
68+ [x ["valid_submit" ] for x in stats ["player_stats" ].values () if x .get ("valid_submit" ) is not None ]
69+ )
70+
71+ ties = stats ["scores" ].get (RESULT_TIE , 0 )
72+ sims = sum (stats ["scores" ].values ())
73+ assert sims >= ties
74+
75+ player2score = {}
76+ for k , v in stats ["player_stats" ].items ():
77+ if k != RESULT_TIE :
78+ if v ["score" ] is None :
79+ # Not sure why this happens, but just skip it
80+ # Kilian: This is probably when we skip a round (might have fixed this, but probably in old logs)
81+ continue
82+ if valid_submits == 1 :
83+ # FOR BACKWARDS COMPATIBILITY: If only one player submitted, give them full point
84+ if v ["valid_submit" ]:
85+ _score = 1.0
86+ else :
87+ _score = 0.0
88+ else :
89+ assert sims > 0 , (stats ["scores" ], valid_submits )
90+ _score = (v ["score" ] + 0.5 * ties ) * 1.0 / sims
91+ player2score [k ] = _score
92+ return player2score
93+
94+
6695def update_profiles (prof_and_score : list [tuple [ModelEloProfile , float ]], k_factor : float ) -> None :
6796 """Update ELO profiles for two players based on their scores
6897
@@ -101,9 +130,12 @@ def __init__(self, *, k_factor: float, starting_elo: float, weighting_function:
101130 self ._alpha = alpha
102131 self ._player_profiles = {}
103132
133+ @property
134+ def player_profiles (self ) -> dict [str , ModelEloProfile ]:
135+ return self ._player_profiles
136+
104137 def _analyze_round (self , stats : dict , player2profile : dict , * , total_rounds : int ) -> None :
105138 """Update all profiles based on the results of one round"""
106- # Calculate round weight
107139 current_round = stats ["round_num" ]
108140 if self ._weighting_function == "linear" :
109141 round_weight = calculate_round_weight_linear (current_round , total_rounds )
@@ -112,36 +144,14 @@ def _analyze_round(self, stats: dict, player2profile: dict, *, total_rounds: int
112144 else : # none
113145 round_weight = 1.0
114146
115- prof_and_score : list [tuple [ModelEloProfile , float ]] = []
116- valid_submits = sum (
117- [x ["valid_submit" ] for x in stats ["player_stats" ].values () if x .get ("valid_submit" ) is not None ]
118- )
147+ player2score = get_scores (stats )
119148
120- # game repetitions
121- ties = stats ["scores" ].get (RESULT_TIE , 0 )
122- # total games
123- sims = sum (stats ["scores" ].values ())
124- assert sims >= ties
125- for k , v in stats ["player_stats" ].items ():
126- if k != RESULT_TIE :
127- if v ["score" ] is None :
128- # Not sure why this happens, but just skip it
129- # Kilian: This is probably when we skip a round (might have fixed this, but probably in old logs)
130- continue
131- if valid_submits == 1 :
132- # FOR BACKWARDS COMPATIBILITY: If only one player submitted, give them full point
133- if v ["valid_submit" ]:
134- _score = 1.0
135- else :
136- _score = 0.0
137- else :
138- assert sims > 0 , (stats ["scores" ], valid_submits )
139- _score = (v ["score" ] + 0.5 * ties ) * 1.0 / sims
140- prof = player2profile [k ]
141- prof .rounds_played += 1
142- prof_and_score .append ((prof , _score ))
149+ prof_and_score = []
150+ for player , score in player2score .items ():
151+ prof = player2profile [player ]
152+ prof .rounds_played += 1
153+ prof_and_score .append ((prof , score ))
143154
144- # Update ELO ratings - should only happen once per match
145155 if len (prof_and_score ) != 2 :
146156 print (f"Skipping round { current_round } (wrong number of players)" )
147157 raise SkipTournamentException
0 commit comments