from math import floor from typing import Tuple from os.path import join, isfile from dataclasses import dataclass from importlib.resources import path from pandas import read_csv, DataFrame from sqlalchemy.orm import sessionmaker from random import randint, getrandbits from names import get_first_name, get_last_name from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import create_engine, Column, String, Integer, not_ MIN_LEVEL = 1 MAX_LEVEL = 10 DEFAULT_COURTS = 12 PLAYER_PER_COURT = 4 Base = declarative_base() class Player(Base): __tablename__ = "players" id = Column("id", Integer, primary_key=True) first = Column("first", String) last = Column("last", String) level = Column("level", Integer) status = Column("status", Integer) count = Column("count", Integer) def __init__( self, id: int = None, first: str = "", last: str = "", level: int = None, status: bool = None, count: int = None, ): self.id = id self.first = first self.last = last self.status = status self.level = level self.count = count def __repr__(self): status = "active" if self.status else "inactive" return f"{self.first} {self.last} (Level {self.level}) is {status} and has played {self.count} games" class DisplayPlayer: id: int first: str last: str status: bool def __init__(self, player: Player): self.id = player.id self.first = player.first self.last = player.last self.status = player.status def __repr__(self): status = "active" if self.status else "inactive" return f"{self.first} {self.last} is {status}" @dataclass class Team: player1: DisplayPlayer player2: DisplayPlayer @dataclass class Game: court: int team1: Team team2: Team @dataclass class CourtList: total: int = DEFAULT_COURTS 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: new_status = not self.courts[court_number] self.courts[court_number] = new_status return new_status def get_courts(self) -> dict: return self.courts 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 class PlayerList: guests: dict = {"low": 0, "mid": 0, "high": 0} def __init__(self, csv_location: str = None) -> None: self._init_database() if csv_location is not None: self._init_database_from_csv(read_csv(csv_location)) else: if not isfile(self.db_location): self._init_random_database() def _init_database(self): with path("match_up") as p: self.db_location = join(p, "players.db") engine = create_engine("sqlite:///" + self.db_location, echo=True) Base.metadata.create_all(bind=engine) self.session = sessionmaker(bind=engine)() def increment_guests(self, level: str): self.guests[level] = self.guests[level] + 1 return self.guests[level] def decrement_guests(self, level: str): if self.guests[level] == 0: return 0 self.guests[level] = self.guests[level] - 1 return self.guests[level] def get_player_status(self, id: int) -> bool: return self.session.query(Player).filter(Player.id == id).first().status def toggle_player_status(self, id: int) -> DisplayPlayer: player = self.session.query(Player).filter(Player.id == id).first() player.status = not player.status self.session.commit() return DisplayPlayer(player) def get_all_players(self) -> list[Player]: all_players = [ DisplayPlayer(p) for p in self.session.query(Player) .order_by(Player.first, Player.last) .all() ] return all_players def get_possible_game_count(self) -> int: total_players = len(self.get_players()) possible_games = floor(total_players / PLAYER_PER_COURT) return possible_games def get_players(self, rounds: int = 0) -> list[Player]: active_players = ( self.session.query(Player) .order_by(Player.first, Player.last) .filter(not_(Player.status == 0)) .all() ) low_guests = [ Player( id=1000 + i, first=f"Beginner", last=f"{i}", level=1, status=True, count=rounds, ) for i in range(1, self.guests["low"] + 1) ] mid_guests = [ Player( id=2000 + i, first=f"Novice", last=f"{i}", level=4, status=True, count=rounds, ) for i in range(1, self.guests["mid"] + 1) ] high_guests = [ Player( id=3000 + i, first=f"Intermediate", last=f"{i}", level=7, status=True, count=rounds, ) for i in range(1, self.guests["high"] + 1) ] return active_players + low_guests + mid_guests + high_guests def increment_game_count(self, player_ids: list[int]): players = self.session.query(Player).filter(Player.id.in_(player_ids)) for player in players: player.count += 1 self.session.commit() def reset_game_count(self): players = self.session.query(Player) for player in players: player.count = 0 self.session.commit() def reset_all_players(self): players = self.session.query(Player) for player in players: player.status = 0 self.session.commit() def _init_database_from_csv(self, data: DataFrame) -> None: self.session.query(Player).delete() for _, entry in data.iterrows(): player = Player( id=entry["id"], first=entry["first"], last=entry["last"], level=entry["skill"], status=False, count=0, ) self.session.add(player) self.session.commit() def _init_random_database(self, player_count: int = 80) -> None: for i in range(player_count): player = Player( id=i, first=get_first_name(), last=get_last_name(), level=randint(MIN_LEVEL, MAX_LEVEL), status=getrandbits(1), count=0, ) self.session.add(player) self.session.commit()