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
|
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",
)
|