from __future__ import annotations from dataclasses import dataclass from datetime import UTC, datetime from typing import TYPE_CHECKING from src.player import Player if TYPE_CHECKING: from src.game import Game from src.strategy import GameEloChangeStrategy @dataclass(frozen=True) class PlayerStatus: player: Player elo: int total_games: int @staticmethod def create(player: Player) -> PlayerStatus: return PlayerStatus(player=player, elo=1000, total_games=0) def update_elo(self, elo_update: int) -> PlayerStatus: return PlayerStatus( player=self.player, elo=self.elo + elo_update, total_games=self.total_games + 1, ) class Ladder: strategy: GameEloChangeStrategy players: dict[Player, PlayerStatus] = { player: PlayerStatus.create(player) for player in Player } def __init__(self,*, strategy: GameEloChangeStrategy) -> None: self.strategy = strategy def current_elo(self) -> dict[Player, int]: return { player: player_status.elo for player, player_status in self.players.items() } def process_game(self, game: Game) -> dict[Player, float]: players_elo_updates = self.strategy.proccess_game(game, self.current_elo()) for player, elo_update in players_elo_updates.items(): self.players[player] = self.players[player].update_elo(int(elo_update)) return players_elo_updates def print_current(self): print(f"Ladder ({datetime.now(tz=UTC).strftime('%d/%m/%Y %H:%M')}):") print("=" * 30) for rank, player in enumerate( sorted(self.players.values(), key=lambda player: player.elo, reverse=True), ): print( f"{rank+1}.\t{player.player.value:<20}: {player.elo:>4d} points, {player.total_games:>3d} games", )