diff options
Diffstat (limited to 'src/match_up/controller.py')
| -rw-r--r-- | src/match_up/controller.py | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/src/match_up/controller.py b/src/match_up/controller.py new file mode 100644 index 0000000..a21fced --- /dev/null +++ b/src/match_up/controller.py @@ -0,0 +1,126 @@ +from typing import Tuple +from operator import attrgetter +from dataclasses import dataclass, field +from match_up.utilities import sample_list, Timer +from match_up.model import ( + Team, + Game, + PlayerList, + CourtList, + MAX_LEVEL, + PLAYER_PER_COURT, +) + + +def _create_placeholders(courts: dict, name: str) -> list[Game]: + dummy_team = Team(player1=name, player2=name) + games = [Game(court, dummy_team, dummy_team) for court in courts] + return games + + +def _normalize_skill(players: dict, new_max: int) -> int: + player_levels = [] + for _, player in players.items(): + skill_level = player.skill + new_level = round((new_max - 1) * (skill_level / MAX_LEVEL)) + 1 + player_levels.append(new_level) + return player_levels + + +def _create_groups_of_four_players(players: dict, new_max: int) -> list[dict]: + player_levels = _normalize_skill(players, new_max) + identifiers = sample_list([*players], player_levels) + clumps = [] + for i in range(0, len(players), PLAYER_PER_COURT): + clumps.append(identifiers[i : i + PLAYER_PER_COURT]) + combinations = [{id: players[id] for id in clump} for clump in clumps] + return combinations + + +def _create_games(courts: dict, players: list[dict], levels: int): + grouped_players = _create_groups_of_four_players(players, levels) + games = [] + for court, players in zip(courts, grouped_players): + ids = [*players] + team1 = Team(player1=players[ids[0]].name, player2=players[ids[3]].name) + team2 = Team(player1=players[ids[1]].name, player2=players[ids[2]].name) + games.append(Game(court, team1, team2)) + return games + + +@dataclass +class RoundGenerator: + courts: CourtList = field(default_factory=lambda: CourtList()) + players: PlayerList = field(default_factory=lambda: PlayerList()) + round: int = 0 + proposal: tuple = tuple() + + def __post_init__(self) -> None: + self.timer = Timer() + self.history = {key: 0 for key, _ in self.players.get_players().items()} + self.games = self._generate_proposal(MAX_LEVEL)[0] + + def _separate_courts(self, courts: dict) -> Tuple[dict, dict]: + possible_games = min(len(courts), self.players.get_possible_game_count()) + courts_as_list = list(courts.items()) + used_courts = dict(courts_as_list[:possible_games]) + unused_courts = dict(courts_as_list[possible_games:]) + return used_courts, unused_courts + + def _select_players(self, count: int) -> dict: + active_players = self.players.get_potential_players() + identifiers = [*active_players] + play_count = [ + ( + self.history[player_id] + if player_id < self.players.guest_id_start + else self.round + ) + for player_id in active_players + ] + ids = sample_list(identifiers, play_count, count) + return {player_id: active_players[player_id] for player_id in ids} + + def _create_inactive_games(self) -> list[Game]: + active_courts, reserved_courts = self.courts.separate_courts() + reserved_games = _create_placeholders(reserved_courts, "RESERVED") + _, unused_courts = self._separate_courts(active_courts) + blank_games = _create_placeholders(unused_courts, "---") + games = reserved_games + blank_games + return games + + def _create_active_games(self, total_levels: int): + active_courts, _ = self.courts.separate_courts() + used_courts, _ = self._separate_courts(active_courts) + required_player_count = len(used_courts) * PLAYER_PER_COURT + selected_players = self._select_players(required_player_count) + games = _create_games(used_courts, selected_players, total_levels) + return games, selected_players + + def _generate_proposal(self, total_levels: int) -> Tuple[list[Game], dict]: + inactive_games = self._create_inactive_games() + active_games, selected_players = self._create_active_games(total_levels) + games = active_games + inactive_games + games.sort(key=attrgetter("court")) + return games, selected_players + + def clear(self) -> list[Game]: + self.proposal = tuple() + return self.games + + def propose(self, levels: int) -> list[Game]: + self.proposal = self._generate_proposal(levels) + return self.proposal[0] + + def confirm(self) -> list[Game]: + proposed_games, proposed_players = self.proposal + if self.games == proposed_games or len(proposed_games) == 0: + return self.games + self.games = proposed_games + for player_id in proposed_players: + if player_id < self.players.guest_id_start: + self.history[player_id] = self.history[player_id] + 1 + self.proposal = tuple() + self.round += 1 + self.timer.start() + return self.games |
