from __future__ import annotations from datetime import datetime class Player: all_players: list[Player] = [] name: str elo: int total_games: int def __init__(self, name: str): self.name = name self.elo = 1000 self.total_games = 0 self.all_players.append(self) def __str__(self): return self.name @staticmethod def print_ladder(): print(f"Ladder ({datetime.now().strftime('%d/%m/%Y %H:%M')}):") print("=" * 30) for rank, player in enumerate( sorted(Player.all_players, key=lambda player: player.elo, reverse=True) ): print( f"{rank+1}.\t{player.name:<20}: {player.elo:>4d} points, {player.total_games:>3d} games" ) Emma = Player(name="Emma") Kim = Player(name="Kim") Pierre = Player(name="Pierre") Theo = Player(name="Théo") Leila = Player(name="Leïla") Martin = Player(name="Martin") Clementine = Player(name="Clémentine") Thomas = Player(name="Thomas") Baptiste = Player(name="Baptiste") Tanguy = Player(name="Tanguy") D = 400 K = 32 class Game: scores: dict[Player, int] played_at: datetime def __str__(self) -> str: total_points = sum(self.scores.values()) return f"Game played at {self.played_at} ({total_points} total points)" def __init__(self, played_at: datetime, scores: dict[Player, int]): self.scores = scores self.played_at = played_at def get_players_elo_updates(self) -> dict[Player, float]: players_elo_updates = {player: 0.0 for player in self.scores} for player in self.scores: player.total_games += 1 for player_1, score_1 in self.scores.items(): for player_2, score_2 in self.scores.items(): if player_1 != player_2: expected_score = 1 / (1 + 10 ** ((player_2.elo - player_1.elo) / D)) result = ( 1.0 if score_1 > score_2 else 0.0 if score_1 < score_2 else 0.5 ) players_elo_updates[player_1] += K * (result - expected_score) return players_elo_updates games: list[Game] = [ Game( datetime(2022, 11, 11, 16, 30), {Theo: 53, Leila: 32, Clementine: 53, Emma: 48, Kim: 50, Martin: 51}, ), Game( datetime(2022, 11, 11, 17, 0), {Emma: 53, Kim: 57, Pierre: 48, Theo: 44, Leila: 32, Martin: 57}, ), Game( datetime(2022, 11, 11, 18, 45), {Thomas: 58, Baptiste: 45, Pierre: 54, Theo: 65, Emma: 42, Martin: 53}, ), Game( datetime(2022, 11, 11, 21, 0), {Kim: 50, Theo: 50, Emma: 53, Clementine: 55, Pierre: 46, Baptiste: 54}, ), Game( datetime(2022, 11, 11, 21, 30), { Kim: 41, Leila: 32, Theo: 48, Emma: 49, Clementine: 52, Pierre: 54, Baptiste: 59, }, ), Game( datetime(2022, 11, 11, 22, 0), {Clementine: 47, Pierre: 46, Theo: 57, Emma: 42} ), Game( datetime(2022, 11, 11, 22, 32), {Clementine: 43, Pierre: 51, Theo: 40, Emma: 39} ), Game( datetime(2022, 11, 12, 12, 48), {Pierre: 58, Theo: 52, Emma: 59, Thomas: 50, Baptiste: 52}, ), Game(datetime(2022, 11, 12, 13, 18), {Emma: 41, Theo: 53, Pierre: 44}), Game(datetime(2022, 11, 12, 13, 47), {Emma: 65, Thomas: 59, Pierre: 54}), Game( datetime(2022, 11, 12, 14, 15), {Pierre: 57, Emma: 52, Martin: 45, Clementine: 47}, ), Game(datetime(2022, 11, 12, 14, 47), {Pierre: 51, Emma: 47, Clementine: 56}), Game( datetime(2022, 11, 12, 19, 6), {Clementine: 43, Kim: 47, Theo: 13, Pierre: 47, Emma: 62}, ), Game( datetime(2022, 11, 13, 12, 31), {Theo: 43, Thomas: 37, Tanguy: 44, Pierre: 47, Emma: 61}, ), Game( datetime(2022, 11, 13, 12, 54), { Tanguy: 54, Clementine: 47, Theo: 65, Thomas: 44, Pierre: 60, Kim: 58, Emma: 46, }, ), Game(datetime(2022, 11, 13, 13, 25), {Pierre: 52, Emma: 68, Clementine: 57}), ] for game in games: print(game) print("=" * 30) players_elo_updates = game.get_players_elo_updates() for (player, elo_update) in players_elo_updates.items(): player.elo += int(elo_update) print(f"\t{player.name:<20}{int(elo_update):+}\t({player.elo:>4d})") Player.print_ladder()