diff --git a/README.md b/README.md index aef916a..d2b6605 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,11 @@ +## Refactored -# work in progress +All models are in `models/models.py` +Sequence can be seen in `controllers/base.py` in the `Controller.run()` method + +for testing purpose, the players_list is created when controller is instantiated + +To test, execute the controllers/base.py +- first menu is called from view +- the method to create player just returns the object (doesn't write anything) +- 1 -> creates a new tournament then run it diff --git a/tournoi/__init_.py b/controllers/__init__.py similarity index 100% rename from tournoi/__init_.py rename to controllers/__init__.py diff --git a/controllers/base.py b/controllers/base.py new file mode 100644 index 0000000..58be14b --- /dev/null +++ b/controllers/base.py @@ -0,0 +1,269 @@ +from ChessTournament.models.models import (Player, Tournament, Round, Match, + MatchHistory) +from ChessTournament.models.models import DATAPATH, PLAYERFILE, TOURNAMENTFILE +from ChessTournament.views.menu import Menu +from ChessTournament.views.base import View + +from random import shuffle +import os +import json + + +class Save: + def __init__(self): + pass + + def load_file(self, file): + try: + os.mkdir(DATAPATH) + except FileExistsError: + pass + # test if file exists... could be done more gracefully + try: + with open(file, "r") as json_file: + data_tmp = json.load(json_file) + return data_tmp + + except json.decoder.JSONDecodeError: + print("Erreur de format sur le fichier") + except FileNotFoundError: + return False + + def write_file(self, data_tmp, file): + with open(file, "w") as json_file: + json_file.write(json.dumps(data_tmp)) + return "Done." + + + def player_write(self, player) -> bool: + data_tmp = [] + if self.load_file(PLAYERFILE): + data_tmp = (self.load_file(PLAYERFILE)) + data_tmp.append(player) + self.write_file(data_tmp, PLAYERFILE) + print("Joueur créé !") + return True + + def player_load(self) -> list: + """Load and create player from JSON file + returns: + list of Player""" + if self.load_file(PLAYERFILE): + data_tmp = self.load_file(PLAYERFILE) + data_list = [] + for player in data_tmp: + data_list.append(Player(name=player['name'], + lastname=player['lastname'], + birthdate=player['birthdate'], + ine=player['ine'])) + + return data_list + else: + print("\n**** Pas de fichier joueur trouvé :/\n") + + def tournament_write(self, tournament): + data = { + tournament.name: tournament.data() + } + print(data) + + if self.load_file(TOURNAMENTFILE): + data_tmp = self.load_file(TOURNAMENTFILE) + data_tmp[tournament.name] = tournament.data() + self.write_file(data_tmp, TOURNAMENTFILE) + else: + self.write_file(data, TOURNAMENTFILE) + return True + + def tournament_load(self): + if self.load_file(TOURNAMENTFILE): + data_tmp = self.load_file(TOURNAMENTFILE) + return data_tmp + else: + print("\n**** Pas de fichier tournoi trouvé :/ \n") + + +class Application: + def __init__(self, tournament, save, view, menu): + self.tournament = tournament + self.save = save + self.match = Match() + self.match_history = MatchHistory() + self.view = view + self.menu = menu + + def sort_by_score(self): + self.tournament.players_list.sort(key=lambda t: t.score, reverse=True) + + def shuffle_players(self): + return shuffle(self.tournament.players_list) + + def create_tournament(self): + print("Nouveau tournoi ! \n") + tournament_details = self.view.prompt_for_tournament() + self.tournament.name = tournament_details['name'] + self.tournament.location = tournament_details['location'] + self.tournament.date_start = tournament_details['date_start'] + self.tournament.date_end = tournament_details['date_end'] + self.tournament.description = tournament_details['description'] + self.tournament.total_round = tournament_details['total_round'] + if self.save.player_load(): + self.tournament.players_list = self.save.player_load() + self.save.tournament_write(self.tournament) + else: + print("Placez un fichier joueur dans le répertoire data" + "ou créez des nouveaux joueurs depuis le menu") + print() + self.menu_manager() + + def run_tournament(self): + shuffle(self.tournament.players_list) + for each_round in range(1, self.tournament.total_round + 1): + self.tournament.current_round += 1 + self.round = Round() + self.round.name = "Round " + str(each_round) + self.view.prompt_for_round(self.round) + # set round start time + self.round.start_time = self.round.get_time() + # create matches TODO : check from history + self.round.match_list = self.create_match() + # display matches + self.view.display_matches(self.round.match_list) + self.view.prompt_for_scores() + self.round.end_time = self.round.get_time() + self.scores(self.round.match_list) + self.sort_by_score() + self.tournament.round_list.append(self.round.save()) + print("après maj", self.tournament.round_list) + self.save.tournament_write(self.tournament) + self.view.display_round_info(self.round) + self.view.display_scores(self.tournament.players_list) + + print("\nLe tournoi", self.tournament.name, "est terminé !\n") + + def get_match_info(self, match_list): + matches = [] + for i in match_list: + matches.append(i.get_data()) + return matches + + def check_match(self, match, match_history): + for item in match_history: + if match in item: + return True + else: + return False + + def create_match(self) -> list: + """Create match with two consecutive players + + returns : + list of Match + """ + match_list = [] + j = 0 + for i in range(0, len(self.tournament.players_list), 2): + j += 1 + match = Match() + match.player1 = self.tournament.players_list[i] + match.player2 = self.tournament.players_list[i+1] + match_list.append(match) + return match_list + + def scores(self, match_list) -> list: + """user asked to enter scores, update Player + returns: + list of tuples + """ + matches = [] + for match in match_list: + count = match_list.index(match) + 1 + result = self.view.input_scores(match, count) + if result in ("1", "2", "3"): + if result == "1": + match.player1.score += 1 + match.score1 = 1 + elif result == "2": + match.player2.score += 1 + match.score2 = 1 + elif result == "3": + match.player1.score += 0.5 + match.player2.score += 0.5 + match.score1 = match.score2 = 0.5 + matches.append(match.get_data()) + return matches + + + def menu_manager(self): + menu_choice = self.menu.items(1) + while True: + # Quit + if menu_choice == "4": + print("Bye") + + # Rapports + elif menu_choice == "3": + rapport_choice = self.menu.items(2) + + # Go back + if rapport_choice == "4": + self.menu_manager() + + # Display players from file + elif rapport_choice == "1": + if self.save.player_load(): + self.view.display_players(self.save.player_load()) + input("?") + + # Display list of tournaments + elif rapport_choice == "2": + if self.save.tournament_load(): + self.view.display_tournaments(self.save.tournament_load()) + input("?") + + # display tournament's details + elif rapport_choice == "3": + temp = {} + if self.save.tournament_load(): + temp = self.save.tournament_load() + name = self.view.prompt_tournament_to_display(temp) + if name in temp: + self.view.display_tournament_detail( + temp[name]) + else: + self.view.display_error() + + # create new player and save it in file + elif menu_choice == "2": + joueur = self.view.prompt_for_new_player() + self.save.player_write(joueur) + input("Retour ?") + self.menu_manager() + + # create new tournament + elif menu_choice == "1": + print("c'est parti") + self.create_tournament() + self.run_tournament() + self.view.display_winner(self.tournament.players_list) + self.view.display_scores(self.tournament.players_list) + self.menu_manager() + + +class CheckMatch: + pass + + +class MenuManager: + pass + + +class TournamentManager: + def __init__(self): + pass + + +class UserManager: + pass + + diff --git a/main.py b/main.py index 9922a62..e64c8c5 100644 --- a/main.py +++ b/main.py @@ -1,40 +1,21 @@ +from ChessTournament.models.models import Tournament +from ChessTournament.controllers.base import Application, Save +from ChessTournament.views.base import View +from ChessTournament.views.menu import Menu + def main(): + tournament = Tournament() + save = Save() + view = View() + menu = Menu() + application = Application(tournament=tournament, + save=save, + view=view, + menu=menu) + # launch application + application.menu_manager() -#Menu -## creer un nouveau tournoi - -## enregistrer un nouveau joueur - -## rapport -### afficher la liste des joueurs inscrits -### liste des tournois -### afficher un tounroi en particulier : -#### liste des joueurs du tournoi (alphab.) -#### liste des tours, matchs - - -# Nouveau Tournoi : -## entrer les infos : -## nom, lieu, date début, date fin, nombre de tours(opt) - -# Participants / joueurs : -## besoin d'enregistrer des nouveaux joueurs ? -## selection des participant dans la liste des joueurs du club - -## Creation du 1er tour : affichage du tour, de la liste des matchs (paire nom.prenom) : -## En attente saisie séquentielle des résultats pour chaque match : -### Saisie résultat match 1 : 1. Bob LEPONGE / 2. Bernard DINAMOUK / 3.Match Nul -### ? - -## Tour suivant (puis itération) : affichage du tour, de la liste des matchs (paire nom.prenom) : -## etc - -## Après le dernier tour : affichage du vainqueur -## sauvegarde du tournoi : tournois/{date.nom.lieu}/{date.nom.lieu}.json, matchs.json -## - -if __name__ == "__main__" : +if __name__ == "__main__": main() - diff --git a/tournoi/match.py b/models/__init__.py similarity index 100% rename from tournoi/match.py rename to models/__init__.py diff --git a/models/models.py b/models/models.py new file mode 100644 index 0000000..c6f93dc --- /dev/null +++ b/models/models.py @@ -0,0 +1,149 @@ +from datetime import datetime +from collections import UserList + +DATAPATH = ("data/") +PLAYERFILE = DATAPATH + "liste_joueurs.json" +TOURNAMENTFILE = DATAPATH + "liste_tournois.json" + + +class Tournament: + """Chess tournament with player_list, keeps a list with all rounds""" + def __init__(self, + name="None", + players_list=None, + location="club", + total_round=4 + ): + self.name = name + self.location = location + self.start = datetime.now().strftime("%d-%m-%Y") + self.end = self.start + self.total_round = total_round + self.round_list = [] + self.current_round = 0 + self.players_list = players_list + self.description = "Pas de description" + + def __str__(self): + return "Tournoi " + self.name + " à " + self.location + + def data(self): + """Save tournament in file""" + players = [] + for i in self.players_list: + # players.append(i.name + " " + i.lastname) + players.append(i.data()) + tournament_dict = { + "name": self.name, + "location": self.location, + "description": self.location, + "start": self.start, + "end": self.end, + "total_rounds": self.total_round, + "current": self.current_round, + "players": players, + "rounds": self.round_list} + return tournament_dict + + +class Player: + """A Chess player""" + def __init__(self, name, lastname, birthdate, ine): + self.lastname = lastname + self.name = name + self.birthdate = birthdate + self.ine = ine + self.score = 0 + + def __str__(self): + """Used in print""" + return self.ine + + def __repr__(self): + return str(self) + + def data(self): + player_dict = { + 'prénom': self.name, + 'nom': self.lastname, + 'date de naissance': self.birthdate, + 'ine': self.ine + } + return player_dict + + +class Match: + def __init__(self, player1=None, player2=None): + self.player1 = player1 + self.player2 = player2 + self.score1 = 0 + self.score2 = 0 + + def __str__(self): + return self.player1.ine + " / " + self.player2.ine + + def get_data(self): + return ([self.player1.ine, self.score1], + [self.player2.ine, self.score2]) + + def get_scores(self) -> list: + return (self.player1.ine + + " : " + str(self.score1) + + " - " + self.player2.ine + + " : " + str(self.score2)) + + +class Round: + + def __init__(self, name="Round 1"): + self.name = name + self.start_time = None + self.end_time = None + self.match_list = [] + + def __str__(self): + return (self.name + + ": début le " + + self.start_time + + " et terminé le " + + self.end_time) + + def get_time(self) -> str: + return datetime.now().strftime("%d-%m-%Y à %Hh%M,%Ss") + + def save(self) -> dict: + matches = [] + for match in self.match_list: + matches.append(match.get_data()) + dico = { + "Nom": self.name, + "Debut": self.start_time, + "Fin": self.end_time, + "Matches": matches + } + return dico + + +class MatchHistory(UserList): + """Keep a history of matches to avoid same match occur + + returns a list of matches + """ + def __init__(self): + self.matches = [] + + def add(self, match_list): + for match in match_list: + self.matches.append(match) + + def __str__(self): + return self.matches + + def check(self, given_match): + for match in self.matches: + if (given_match.player1 == match.player1 + or given_match.player1 == match.player2): + if (given_match.player2 == match.player2 + or given_match.player2 == match.player2): + return True + return False diff --git a/tournoi/menu.py b/tournoi/menu.py deleted file mode 100644 index 38c347d..0000000 --- a/tournoi/menu.py +++ /dev/null @@ -1,14 +0,0 @@ -class Menu: - - def items(self): - print("[1] Créer un nouveau tournoi", end='\n') - print("[2] Enregistrer un nouveau joueur", end='\n') - print("[3] Rapports", end='\n') - print("[4] Quitter", end='\n') - - - def rapports(): - print("[1] Afficher la liste des joueurs", end='\n') - print("[2] Afficher l'historique des tournois", end='\n') - print("[3] Afficher le détail d'un tournoi", end='\n') - print("[4] Quitter", end='\n') diff --git a/tournoi/player.py b/tournoi/player.py deleted file mode 100644 index d64df1e..0000000 --- a/tournoi/player.py +++ /dev/null @@ -1,19 +0,0 @@ -import json - -class Player: - """Define player, should store only data for now ? Don't see further""" - - def get_new_player(self): - get_player = {} - print("Enregistrez un nouveau joueur :\n") - get_player['lastname'] = input('Nom de famille :\n') - get_player['name'] = input('Prénom :\n') - get_player['birth_date'] = input('Date de naissance :\n') - - #convert dict in json object and write it in players.json file (with "a" append to file) - with open("players.json", "a") as output: - output.write(json.dumps(get_player, indent=3)) - - -new = Player() -new.get_new_player() diff --git a/tournoi/players.json b/tournoi/players.json deleted file mode 100644 index 27e7345..0000000 --- a/tournoi/players.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "lastname": "Prout", - "name": "Joe", - "birth_date": "23/02/2003" -} -{ - "lastname": "Dupont", - "name": "Pierre", - "birth_date": "20/01/2002" -} \ No newline at end of file diff --git a/tournoi/turn.py b/tournoi/turn.py deleted file mode 100644 index c48c80b..0000000 --- a/tournoi/turn.py +++ /dev/null @@ -1,74 +0,0 @@ -from random import choice - - -class Turn(): - def __init__(self, name, matchs): - self.name = name - self.matchs = matchs - self.match_history = [] - - def rambling(self, player_list): - """jumble (random order) players in list and return list""" - self.tmp_list = [] - self.picked_player = [] - for i in range(2^len(player_list)): - self.picked_player = choice(player_list) - self.tmp_list.append(self.picked_player) - return self.tmp_list - - - def sorting(self, player_list): - """order players on score : use second index (for every item in the list) as key (given by function score)""" - def score(couple): - return couple[1] - return sorted(player_list, key=score) - - - def associate(self, player_list): - """create a match list""" - self.match_list = [] - self.couple = () - for i in range(len(player_list)): - if i % 2 == 0 : - self.couple = (player_list[i][0], player_list[i+1][0]) - if self.couple in self.match_history: - self.couple = (player_list[i][0], player_list[i + 2][0]) - self.match_list.append(self.couple) - else: - self.match_list.append(self.couple) - - self.match_history.append(self.name) - self.match_history.append(self.match_list) - return self.match_list - - - def matchmarking(self, player_list): - pass - -list = [['Player1', 8], - ['Player2', 2], - ['Player3', 0], - ['Player4', 5], - ['Player5', 8], - ['Player6', 3], - ['Player7', 1], - ['Player8', 6], - ['Player9', 3], - ['Player10', 4], - ['Player11', 3], - ['Player12', 2], - ['Player13', 8], - ['Player14', 4], - ['Player15', 2], - ['Player16', 7]] - -tour = Turn("tour1", 1) - -print(tour.sorting(list)) -print(tour.rambling(list)) - -print(tour.associate(tour.sorting(list))) - -print(f"Voici l'historique des matchs : {tour.match_history}") - -tour2 = Turn() \ No newline at end of file diff --git a/tournoi/tournament.py b/views/__init__.py similarity index 100% rename from tournoi/tournament.py rename to views/__init__.py diff --git a/views/base.py b/views/base.py new file mode 100644 index 0000000..70fb14f --- /dev/null +++ b/views/base.py @@ -0,0 +1,142 @@ +from datetime import datetime +import re + + +class View: + """Prompt menu, get choices""" + def __init__(self): + pass + + def check_date(self): + while True: + date = input("Date de naissance (jj/mm/aaaa) ? : ") + if datetime.strptime(date, '%d/%m/%Y'): + break + else: + print("La date doit être au format jj/mm/aaaa") + + def test_ine(self): + ine_pattern = r'[a-zA-Z]{2}\d{5}' + while True: + ine = input("Identifiant National d'Echecs (ine) ? : ") + if re.match(ine_pattern, ine): + break + else: + print("Mauvais format d'ine") + + def prompt_for_scores(self): + print() + input("Saisir les scores ? (y)") + return True + + def prompt_for_round(self, round): + print() + input(f"Prêt à lancer le {round.name} ? (y)") + return True + + def display_matches(self, match_list): + print("Liste des matchs : ") + for match in match_list: + print(match.player1.name, match.player1.lastname.upper(), + "contre", match.player2.name, match.player2.lastname.upper(), + "(", match, ")" + ) + + def display_round_info(self, round): + print("\n -> ", round) + + def display_scores(self, players_list): + print("\nLes scores sont :") + print("-----------------") + for i in players_list: + print(i.ine, i.name, i.lastname, ":", i.score) + + def prompt_for_new_player(self) -> dict: + print("Enregistrez un nouveau joueur :\n") + lastname = input("Nom de famille ? : ") + name = input("Prénom ? : ") + birthdate = input("Date de naissance (jj/mm/aaaa) ? : ") + ine = input("Identifiant National d'Echecs (ine) ? : ") + return {'name': name, + 'lastname': lastname, + 'birthdate': birthdate, + 'ine': ine} + + def prompt_for_tournament(self) -> dict: + tournament_details = {} + tournament_details['name'] = str.lower(input("Nom du tournoi ? : ")) + tournament_details['location'] = str.lower(input("Lieu du tournoi : ")) + tournament_details['date_start'] = ( + input("date de début (jj/mm/aaaa) : [today] " + or datetime.now().strftime("%d/%m/%Y"))) + tournament_details['date_end'] = ( + input("date de fin (jj/mm/aaaa) : [today] " + or datetime.now().strftime("%d/%m/%Y"))) + tournament_details['description'] = input("Description ? : ") + total_round = input("Nombre de tours ? (4 par défaut) : ") or 4 + tournament_details['total_round'] = int(total_round) + return tournament_details + + def input_scores(self, match, count): + print("Scores pour le match", count, " :") + while True: + try: + result = input(f"1.{match.player1}, " + f"2.{match.player2}, " + f"3.Nul\n") + if result in ("1", "2", "3"): + return result + else: + print("Entrez un chiffre entre 1 et 3") + except ValueError: + print("Veuillez entrer un chiffre") + + def display_winner(self, player_list): + winner = max(player_list, key=lambda t: t.score) + print("Le gagnant est :", + winner.name, + winner.lastname, + "avec un score de :", + winner.score) + + def display_players(self, player_list_to_display): + print("Liste des joueurs :") + for player in player_list_to_display: + print(player.data()) + + def display_tournaments(self, tournament_list_to_display): + print("Liste des tournois : ") + for tournament in tournament_list_to_display: + print("-", tournament, + "le", + tournament_list_to_display[tournament]['start']) + + def prompt_tournament_to_display(self, tournament_list_to_display): + i = 0 + temp_list = [] + for tournament in tournament_list_to_display: + i += 1 + print(i, ".", tournament) + temp_list.append(tournament) + num = int(input("Numéro du tournoi à afficher ? ")) + return temp_list[num - 1] + + def display_tournament_detail(self, tournament_to_display): + i = tournament_to_display + print("Nom du tournoi : ", i['name']) + print("Lieu : ", i['location']) + print("Le tournoi a débuté le : ", i['start']) + print("Et s'est terminé le : ", i['end']) + print("Les participants étaient : \n", i['players']) + print("\nLes matches et leurs résultats étaient :") + for j in i['rounds']: + print(j['Nom']) + print("Commencé à ", j['Debut']) + print("Terminé à ", j['Fin']) + print("Liste des matchs :") + for k in j['Matches']: + print(k) + print() + + def display_error(self): + print("Erreur de saisie, recommencez;") diff --git a/views/menu.py b/views/menu.py new file mode 100644 index 0000000..378685e --- /dev/null +++ b/views/menu.py @@ -0,0 +1,38 @@ + +class Menu: + def __init__(self): + self.ITEMS = [ + "[1] Créer un nouveau tournoi", + "[2] Enregistrer un nouveau joueur", + "[3] Rapports", + "[4] Quitter" + ] + self.RAPPORTS = [ + "[1] Afficher la liste des joueurs", + "[2] Afficher l'historique des tournois", + "[3] Afficher le détail d'un tournoi", + "[4] Retour" + ] + + def items(self, value): + """displays menu depending on given value""" + menu_type = [] + if value == 1: + menu_type = self.ITEMS + print() + print("MENU GENERAL") + if value == 2: + menu_type = self.RAPPORTS + print() + print("MENU RAPPORTS") + for i in menu_type: + print(i) + while True: + try: + choice = input("Choix ? : ") + if int(choice) not in range(1, len(menu_type) + 1): + print("Choisissez un chiffre entre 1 et", len(menu_type)) + else: + return choice + except ValueError: + print("Veuillez entrer un chiffre") diff --git a/vrac.py b/vrac.py deleted file mode 100644 index ca61ba2..0000000 --- a/vrac.py +++ /dev/null @@ -1,7 +0,0 @@ -# generate player list -from random import randint - -list = [] -for i in range(16): - list.append(["Player"+str(i+1), randint(0, 8)]) -