|
6 | 6 |
|
7 | 7 | from tqdm import tqdm |
8 | 8 |
|
| 9 | +from codeclash.analysis.viz.utils import MODEL_TO_DISPLAY_NAME |
9 | 10 | from codeclash.constants import LOCAL_LOG_DIR, RESULT_TIE |
| 11 | +from codeclash.games import ARENAS |
10 | 12 |
|
11 | 13 |
|
12 | 14 | @dataclass |
@@ -221,18 +223,71 @@ def print_results(self) -> None: |
221 | 223 |
|
222 | 224 | print("\nELO per player (across all games):") |
223 | 225 | calc_avg_elo = lambda total_elo, games: total_elo / games |
| 226 | + model_to_avg_elo = {mid: calc_avg_elo(weighted_elo[mid], total_games[mid]) for mid in weighted_elo} |
224 | 227 | lines = sorted( |
225 | | - [ |
226 | | - f"{pid}: {calc_avg_elo(weighted_elo[pid], total_games[pid]):.1f} (Rounds: {total_games[pid]})" |
227 | | - for pid in weighted_elo |
228 | | - if total_games[pid] > 0 |
229 | | - ], |
| 228 | + [f"{pid}: {model_to_avg_elo[pid]:.1f} (Rounds: {total_games[pid]})" for pid in model_to_avg_elo.keys()], |
230 | 229 | key=lambda x: float(x.split(":")[1].split("(")[0]), |
231 | 230 | reverse=True, |
232 | 231 | ) |
233 | 232 | for i, line in enumerate(lines, 1): |
234 | 233 | print(f"{i}. {line}") |
235 | 234 |
|
| 235 | + # Print latex formatted table for results, formatted as |
| 236 | + # Model & ELO & & & \\ |
| 237 | + # & BattleCode & BattleSnake & ... \\ |
| 238 | + # \midrule |
| 239 | + # Claude 4 Sonnet & ... & & & \\ |
| 240 | + # ... |
| 241 | + print("\nLaTeX formatted table:") |
| 242 | + arenas = [x.name for x in ARENAS] |
| 243 | + lines = [] |
| 244 | + arenas_small = [f"\\scriptsize{{{arena}}}" for arena in arenas] |
| 245 | + line = "& " + " & ".join(arenas_small) + " & All" + r" \\" |
| 246 | + line = line.replace("HuskyBench", "Poker") |
| 247 | + lines.append(line) |
| 248 | + lines.append(r"\midrule") |
| 249 | + per_model_lines = {} |
| 250 | + arena_rankings = {} |
| 251 | + |
| 252 | + # Create a mapping of model -> arena -> elo and also arena -> list of (model, elo) for ranking |
| 253 | + for profile in self._player_profiles.values(): |
| 254 | + if profile.model not in per_model_lines: |
| 255 | + per_model_lines[profile.model] = {} |
| 256 | + if profile.arena not in arena_rankings: |
| 257 | + arena_rankings[profile.arena] = [] |
| 258 | + per_model_lines[profile.model][profile.arena] = round(profile.rating, 1) |
| 259 | + arena_rankings[profile.arena].append((profile.model, profile.rating)) |
| 260 | + |
| 261 | + # Sort each arena ranking by ELO descending |
| 262 | + for arena in arena_rankings: |
| 263 | + arena_rankings[arena].sort(key=lambda x: x[1], reverse=True) |
| 264 | + for rank, (model, _) in enumerate(arena_rankings[arena], 1): |
| 265 | + per_model_lines[model][arena] = ( |
| 266 | + f"{per_model_lines[model][arena]}" + f"\\textsuperscript{{\\textcolor{{gray}}{{{rank}}}}}" |
| 267 | + ) |
| 268 | + if rank == 1: |
| 269 | + # Make it bold |
| 270 | + per_model_lines[model][arena] = f"\\textbf{{{per_model_lines[model][arena]}}}" |
| 271 | + |
| 272 | + # Now print the table |
| 273 | + overall_ranks = sorted(model_to_avg_elo.items(), key=lambda x: x[1], reverse=True) |
| 274 | + model_rank = {model: rank + 1 for rank, (model, _) in enumerate(overall_ranks)} |
| 275 | + for model in sorted(per_model_lines.keys()): |
| 276 | + m = model.split("/", 1)[-1] |
| 277 | + rank = f"\\textsuperscript{{\\textcolor{{gray}}{{{model_rank[model]}}}}}" |
| 278 | + overall_elo = f"{model_to_avg_elo[model]:.1f}{rank}" |
| 279 | + if model_rank[model] == 1: |
| 280 | + overall_elo = f"\\textbf{{{overall_elo}}}" |
| 281 | + line = ( |
| 282 | + f"\\small{{{MODEL_TO_DISPLAY_NAME[m]}}} & " |
| 283 | + + " & ".join(str(per_model_lines[model].get(arena, "-")) for arena in arenas) |
| 284 | + + " & " |
| 285 | + + overall_elo |
| 286 | + + " \\\\" |
| 287 | + ) |
| 288 | + lines.append(line) |
| 289 | + print("\n".join(lines)) |
| 290 | + |
236 | 291 |
|
237 | 292 | if __name__ == "__main__": |
238 | 293 | parser = argparse.ArgumentParser(description="Calculate weighted ELO ratings with configurable weighting functions") |
|
0 commit comments