From 7200fcf3f4e4c22193b5b96452f9aa5131b1bc1c Mon Sep 17 00:00:00 2001 From: Martin Kagamino Lehoux Date: Sun, 19 Feb 2023 12:57:27 +0100 Subject: refactor: Move to src --- game.py | 14 -------------- ladder.py | 56 -------------------------------------------------------- main.py | 8 ++++---- player.py | 17 ----------------- src/__init__.py | 0 src/game.py | 14 ++++++++++++++ src/ladder.py | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/player.py | 17 +++++++++++++++++ src/strategy.py | 40 ++++++++++++++++++++++++++++++++++++++++ strategy.py | 36 ------------------------------------ 10 files changed, 131 insertions(+), 127 deletions(-) delete mode 100644 game.py delete mode 100644 ladder.py delete mode 100644 player.py create mode 100644 src/__init__.py create mode 100644 src/game.py create mode 100644 src/ladder.py create mode 100644 src/player.py create mode 100644 src/strategy.py delete mode 100644 strategy.py diff --git a/game.py b/game.py deleted file mode 100644 index 8c88f6e..0000000 --- a/game.py +++ /dev/null @@ -1,14 +0,0 @@ -from dataclasses import dataclass -from datetime import datetime - -from player import Player - - -@dataclass(frozen=True) -class Game: - played_at: datetime - scores: dict[Player, int] - - def __str__(self) -> str: - total_points = sum(self.scores.values()) - return f"Game played at {self.played_at} ({total_points} total points)" diff --git a/ladder.py b/ladder.py deleted file mode 100644 index 7351798..0000000 --- a/ladder.py +++ /dev/null @@ -1,56 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass -from datetime import datetime - -from game import Game -from player import Player -from 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 current_elo(self) -> dict[Player, int]: - return { - player: player_status.elo for player, player_status in self.players.items() - } - - def proccess_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().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", - ) diff --git a/main.py b/main.py index 6cfe64d..44e73e3 100644 --- a/main.py +++ b/main.py @@ -1,9 +1,9 @@ from datetime import datetime -from game import Game -from ladder import Ladder -from player import Player -from strategy import SimpleEloChangeStrategy +from src.game import Game +from src.ladder import Ladder +from src.player import Player +from src.strategy import SimpleEloChangeStrategy ladder = Ladder() ladder.strategy = SimpleEloChangeStrategy() diff --git a/player.py b/player.py deleted file mode 100644 index 961f51a..0000000 --- a/player.py +++ /dev/null @@ -1,17 +0,0 @@ -from enum import Enum - - -class Player(Enum): - Emma = "Emma" - Kim = "Kim" - Pierre = "Pierre" - Theo = "Théo" - Leila = "Leïla" - Martin = "Martin" - Clementine = "Clémentine" - Thomas = "Thomas" - Baptiste = "Baptiste" - Tanguy = "Tanguy" - Frost = "Frost" - Felix = "Félix" - Axel = "Axel" diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/game.py b/src/game.py new file mode 100644 index 0000000..0e8803c --- /dev/null +++ b/src/game.py @@ -0,0 +1,14 @@ +from dataclasses import dataclass +from datetime import datetime + +from src.player import Player + + +@dataclass(frozen=True) +class Game: + played_at: datetime + scores: dict[Player, int] + + def __str__(self) -> str: + total_points = sum(self.scores.values()) + return f"Game played at {self.played_at} ({total_points} total points)" diff --git a/src/ladder.py b/src/ladder.py new file mode 100644 index 0000000..8603e9d --- /dev/null +++ b/src/ladder.py @@ -0,0 +1,56 @@ +from __future__ import annotations + +from dataclasses import dataclass +from datetime import datetime + +from src.game import Game +from src.player import Player +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 current_elo(self) -> dict[Player, int]: + return { + player: player_status.elo for player, player_status in self.players.items() + } + + def proccess_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().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", + ) diff --git a/src/player.py b/src/player.py new file mode 100644 index 0000000..961f51a --- /dev/null +++ b/src/player.py @@ -0,0 +1,17 @@ +from enum import Enum + + +class Player(Enum): + Emma = "Emma" + Kim = "Kim" + Pierre = "Pierre" + Theo = "Théo" + Leila = "Leïla" + Martin = "Martin" + Clementine = "Clémentine" + Thomas = "Thomas" + Baptiste = "Baptiste" + Tanguy = "Tanguy" + Frost = "Frost" + Felix = "Félix" + Axel = "Axel" diff --git a/src/strategy.py b/src/strategy.py new file mode 100644 index 0000000..6713299 --- /dev/null +++ b/src/strategy.py @@ -0,0 +1,40 @@ +from typing import Protocol + +from src.game import Game +from src.player import Player + + +class GameEloChangeStrategy(Protocol): + def proccess_game( + self, + game: Game, + current_elo: dict[Player, int], + ) -> dict[Player, float]: + ... + + +class SimpleEloChangeStrategy(GameEloChangeStrategy): + D = 400 + K = 32 + + def proccess_game( + self, + game: Game, + current_elo: dict[Player, int], + ) -> dict[Player, float]: + players_elo_updates = {player: 0.0 for player in game.scores} + + for player_1, score_1 in game.scores.items(): + for player_2, score_2 in game.scores.items(): + if player_1 != player_2: + expected_score = 1 / ( + 1 + + 10 + ** ((current_elo[player_2] - current_elo[player_1]) / self.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] += self.K * (result - expected_score) + + return players_elo_updates diff --git a/strategy.py b/strategy.py deleted file mode 100644 index 5f42e3f..0000000 --- a/strategy.py +++ /dev/null @@ -1,36 +0,0 @@ -from typing import Protocol - -from game import Game -from player import Player - - -class GameEloChangeStrategy(Protocol): - def proccess_game( - self, game: Game, current_elo: dict[Player, int], - ) -> dict[Player, float]: - ... - - -class SimpleEloChangeStrategy(GameEloChangeStrategy): - D = 400 - K = 32 - - def proccess_game( - self, game: Game, current_elo: dict[Player, int], - ) -> dict[Player, float]: - players_elo_updates = {player: 0.0 for player in game.scores} - - for player_1, score_1 in game.scores.items(): - for player_2, score_2 in game.scores.items(): - if player_1 != player_2: - expected_score = 1 / ( - 1 - + 10 - ** ((current_elo[player_2] - current_elo[player_1]) / self.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] += self.K * (result - expected_score) - - return players_elo_updates -- cgit v1.3