from math import floor from csv import reader from pathlib import Path from random import sample from operator import attrgetter from dataclasses import dataclass from typing import Tuple @dataclass class CourtList: total: int def __post_init__(self) -> None: self.courts = {i + 1: True for i in range(self.total)} def get_court_status(self, court_number: int) -> bool: return self.courts[court_number] def toggle_court_status(self, court_number: int) -> None: current_status = self.courts[court_number] self.courts[court_number] = not current_status return not current_status def separate_courts(self) -> Tuple[dict, dict]: active_courts = {k: v for k, v in self.courts.items() if v} inactive_courts = {k: v for k, v in self.courts.items() if not v} return active_courts, inactive_courts @dataclass class Player: name: str skill: int = 0 status: bool = True def create_player_from_row(row: list[str]) -> Player: return Player(name=row[0], skill=row[1], status=(row[2] == "True")) class PlayerList: def __init__(self, location: Path = "players.csv"): with open(location, newline="") as file: data_reader = reader(file) next(data_reader, None) players = [create_player_from_row(row) for row in data_reader] players.sort(key=attrgetter("name")) self.players = players def get_player(self, player_request: str): players = [player for player in self.players if player.name == player_request] players.sort(key=attrgetter("name")) return players def get_active_players(self): players = [player for player in self.players if player.status] players.sort(key=attrgetter("name")) return players def toggle_player(self, player_request: Player): self.players = [ ( Player( name=player.name, skill=player.skill, status=not player.status, ) if player.name == player_request else player ) for player in self.players ] def __str__(self): display_string = "" for player in self.players: display_string += player.__str__() + "\n" return display_string @dataclass class Team: player1: Player player2: Player @dataclass class Game: court: int team1: Team team2: Team DUMMY_PLAYER = Player(name="-") DUMMY_TEAM = Team(player1=DUMMY_PLAYER, player2=DUMMY_PLAYER) def create_dummy_games(courts: dict): return [Game(court, DUMMY_TEAM, DUMMY_TEAM) for court, _ in courts.items()] RESERVED_PLAYER = Player(name="Reserved") RESERVED_TEAM = Team(player1=RESERVED_PLAYER, player2=RESERVED_PLAYER) def create_reserved_games(courts: dict): return [Game(court, RESERVED_TEAM, RESERVED_TEAM) for court, _ in courts.items()] PLAYER_PER_COURT = 4 def create_game(court: int, players: list[Player]): team1 = Team(player1=players[0], player2=players[3]) team2 = Team(player1=players[1], player2=players[2]) return Game(court, team1, team2) def create_possible_games(courts: dict, players: list[Player]): count = len(players) clumped_players = [ players[i : i + PLAYER_PER_COURT] for i in range(0, count, PLAYER_PER_COURT) ] games = [create_game(court, clump) for court, clump in zip(courts, clumped_players)] return games @dataclass class GameList: def clear(self, court_list: CourtList): active_courts, inactive_courts = court_list.separate_courts() dummy_games = create_dummy_games(active_courts) reserved_games = create_reserved_games(inactive_courts) games = dummy_games + reserved_games games.sort(key=attrgetter("court")) self.games = games def create_random_games(self, courts: CourtList, player_list: PlayerList): active_players = player_list.get_active_players() active_courts, inactive_courts = courts.separate_courts() possible_games = floor(len(active_players) / PLAYER_PER_COURT) if possible_games > len(active_courts): possible_games = len(active_courts) current_players = sample(active_players, possible_games * PLAYER_PER_COURT) active_games = create_possible_games( dict(list(active_courts.items())[:possible_games]), current_players ) dummy_games = create_dummy_games( dict(list(active_courts.items())[possible_games:]) ) reserved_games = create_reserved_games(inactive_courts) games = active_games + dummy_games + reserved_games games.sort(key=attrgetter("court")) self.games = games def create_skilled_games(self, courts: CourtList, player_list: PlayerList): active_players = player_list.get_active_players() active_courts, inactive_courts = courts.separate_courts() possible_games = floor(len(active_players) / PLAYER_PER_COURT) if possible_games > len(active_courts): possible_games = len(active_courts) current_players = sample(active_players, possible_games * PLAYER_PER_COURT) current_players.sort(key=attrgetter("skill")) active_games = create_possible_games( dict(list(active_courts.items())[:possible_games]), current_players ) dummy_games = create_dummy_games( dict(list(active_courts.items())[possible_games:]) ) reserved_games = create_reserved_games(inactive_courts) games = active_games + dummy_games + reserved_games games.sort(key=attrgetter("court")) self.games = games