Compare commits

...

31 Commits
main ... dev

Author SHA1 Message Date
c1a0a79531 fix reversed method name 2025-02-14 19:54:52 +01:00
aea638d660 remove prints and inputs from controller to view 2025-02-14 11:49:52 +01:00
c9cf13c209 last run to be clean 2025-02-13 19:03:37 +01:00
9b881839ba display tournament prettier 2025-02-13 19:00:46 +01:00
5d4aa8127f add space 2025-02-13 18:58:39 +01:00
d09e781ded quit from menu to avoid loop 2025-02-13 18:56:46 +01:00
2397e6dbe4 removed unused methods 2025-02-13 18:27:46 +01:00
a1c7b5ab2c reset round list for a new tournament 2025-02-13 16:38:44 +01:00
52ae8b774d fix typo 2025-02-13 16:20:03 +01:00
fee2df07b1 add lines in display 2025-02-13 16:13:11 +01:00
fd87fabaf1 improve player display 2025-02-13 16:08:21 +01:00
cebb11380c fix modules path 2025-02-13 16:00:03 +01:00
653e3ef0f6 add move in right folder 2025-02-13 15:58:05 +01:00
89bda57fe5 Merge pull request 'simple' (#4) from simple into dev
Reviewed-on: #4
2025-02-13 14:52:08 +00:00
89aa9b2192 add info 2025-02-13 15:51:31 +01:00
98c723afc5 generate new flake report 2025-02-13 15:46:37 +01:00
6043354279 Merge pull request 'simple' (#3) from simple into dev
Reviewed-on: #3
2025-02-13 14:44:48 +00:00
29a56eceaa adjust match issue, add total score to tournament display 2025-02-13 15:44:04 +01:00
d115126afb remove some remaining debug prints 2025-02-13 12:07:52 +01:00
bc8f73beaf add break on quit to avoid loop 2025-02-13 12:02:08 +01:00
31c2b39fa4 fix some minor issues 2025-02-13 12:01:01 +01:00
7c50729643 Merge pull request 'add flake report and instructions' (#2) from simple into dev
Reviewed-on: #2
2025-02-13 10:54:47 +00:00
151b2411b3 add flake report and instructions 2025-02-13 11:49:04 +01:00
cd14f05d54 Merge pull request 'simple' (#1) from simple into dev
Reviewed-on: #1
2025-02-13 10:32:13 +00:00
a0f7004c7f reorganized everything, put launcher in main 2025-02-13 11:26:15 +01:00
0500dbeb7a improve round display with dunder 2025-02-06 11:25:56 +01:00
a0cb9b0e12 delete unused old models 2025-02-06 10:26:48 +01:00
6df0cf99fe add some explanation on sequence and tests 2025-02-06 10:23:57 +01:00
195c3f6b02 moved some methods to view 2025-02-06 10:16:16 +01:00
425c5c716b tournament works.. but things are not in the right place 2025-02-05 15:20:11 +01:00
04aa65f2a8 refactored from simpliest models 2025-02-05 13:47:52 +01:00
23 changed files with 1123 additions and 503 deletions

View File

@ -1,2 +1,60 @@
# Gestion des tournois
# work in progress ## Introduction
Ces instructions vous permettent de :
- récupérer le programme,
- d'installer l'environnement nécessaire à son exécution,
- de l'exécuter,
- de l'utiliser
### Pré-requis
```
paquets : python 3.11, python3.11-venv, git
```
### Installation
Voici les étapes à suivre pour avoir un environnement d'exécution opérationnel :
créer l'environnement virtuel
```
python3.11 -m venv env
source env/bin/activate
```
cloner le dépôt, aller dans le bon dossier
```
git clone https://mcstn.fr/gitea/Yann/Projet4.git
cd Projet4
```
## Exécution
exécuter la commande :
```
python3 main.py
```
## Utilisation
Toutes les actions se font via le menu affiché.
Il y a deux menus : général et rapport.
Si vous souhaitez spécifier une liste de joueurs au format JSON, il vous faut la placer
dans le répertoire `data`
Sinon, vous pouvez créer des joueurs via le menu
Le répertoire, nom des fichiers joueurs et tournois sont des constantes de models.py
Ils sont placés dans le dossier `data`
## Auteur
Yann <yann@needsome.coffee>
## License
N/A

View File

@ -1,61 +1,244 @@
from models.tournament import Tournament from models.models import (Player, Round, Match, MatchHistory)
from models.player import Player from models.models import DATAPATH, PLAYERFILE, TOURNAMENTFILE
from models.turn import Turn
from models.match import Match
from views.menu import Menu
class Controller: from random import shuffle
def __init__(self): import os
# loading models import json
self.players_list: List[Player] = []
self.score_list = []
class Save:
def __init__(self, view):
self.view = view
# loading views def load_file(self, file):
self.view = Menu()
#self.tournament = Tournament(name = "Tournoi de Cajou", )
#self.turn = Turn()
def prompt_menu(self):
pass
def record_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')
self.lastname = input("Nom de famille ? :\n")
self.name = input("Prénom ? :\n")
def input_date(date):
"""Keep asking until date format is valid"""
try: try:
datetime.strptime(date, '%d/%m/%Y') os.mkdir(DATAPATH)
return date except FileExistsError:
except ValueError: pass
print("La date doit être au format jj/mm/aaaa") # test if file exists... could be done more gracefully
new_date = input() try:
input_date(new_date) with open(file, "r") as json_file:
return new_date data_tmp = json.load(json_file)
return data_tmp
self.birthdate = input_date(input("Date de naissance (jj/mm/aaaa) ?:\n")) except json.decoder.JSONDecodeError:
self.view.display_format_error()
except FileNotFoundError:
return False
while self.gender not in ("M", "F", "N"): def write_file(self, data_tmp, file):
self.gender = input("Sexe (M/F/N) ?:\n") with open(file, "w") as json_file:
json_file.write(json.dumps(data_tmp))
return "Done."
# convert dict in json object and write it in players.json file (with "a" append to file) def player_write(self, player) -> bool:
# with open("players.json", "a") as output: data_tmp = []
# output.write(json.dumps(get_player, indent=3)) if self.load_file(PLAYERFILE):
data_tmp = (self.load_file(PLAYERFILE))
data_tmp.append(player)
self.write_file(data_tmp, PLAYERFILE)
self.view.ok_player()
return True
return {"Nom": self.lastname, "Prénom": self.name, "Date de naissance": self.birthdate, "Genre": self.gender} 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']))
def run(self): return data_list
else:
self.view.display_file_error("joueur")
menu_choice = self.view.items(1) def tournament_write(self, tournament):
if menu_choice == 3: data = {
self.view.items(2) tournament.name: tournament.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:
self.view.display_file_error("tournoi")
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 create_tournament(self):
"""update existing tournament with data from view"""
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']
self.tournament.round_list = []
if self.save.player_load():
self.tournament.players_list = self.save.player_load()
self.save.tournament_write(self.tournament)
else:
self.view.display_player_instructions()
self.menu_manager()
def run_tournament(self):
"""creates all round iteration
"""
shuffle(self.tournament.players_list)
self.view.display_players(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()
self.match_history.add(self.round.match_list)
# 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())
self.save.tournament_write(self.tournament)
self.view.display_round_info(self.round)
self.view.display_scores(self.tournament.players_list)
self.view.ok_done(self.tournament.name)
def check_match(self, match, match_history):
"""check if match is in list
For future usage
"""
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()
try:
match.player1 = self.tournament.players_list[i]
match.player2 = self.tournament.players_list[i+1]
if self.match_history.check(match):
# match.player2 = self.tournament.players_list[i+2]
self.view.display_error_already()
match_list.append(match)
except IndexError:
pass
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":
self.view.display_quit()
quit()
# 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())
self.view.prompt_next()
# Display list of tournaments
elif rapport_choice == "2":
if self.save.tournament_load():
self.view.display_tournaments(
self.save.tournament_load())
self.view.prompt_next()
# 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)
self.view.prompt_next()
self.menu_manager()
# create new tournament
elif menu_choice == "1":
self.view.ok_go()
self.create_tournament()
self.run_tournament()
self.menu_manager()

View File

@ -1 +0,0 @@
{"EF34924": ["Bob", "Durand", "25/12/1995", "M"], "QS42622": ["Joe", "Bidjoba", "02/01/2001", "M"], "AB20022": ["Jeanine", "Mequesurton", "25/12/1995", "F"], "JF78739": ["Jean-Pierre", "Quiroul", "15/09/1992", "M"], "ED22230": ["Ren\u00e9", "Nuphard", "25/12/1995", "M"], "EE49948": ["Sophie", "Fonfec", "24/05/1999", "F"]}

73
flake-report/back.svg Normal file
View File

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="32"
height="48"
viewBox="0 0 32 48"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="back.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#3d3d3d"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="4"
inkscape:cx="47.245066"
inkscape:cy="13.218734"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
width="32px"
inkscape:window-width="1535"
inkscape:window-height="876"
inkscape:window-x="65"
inkscape:window-y="24"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-1004.3622)">
<g
id="g5305"
transform="translate(0,-3.5)">
<path
inkscape:connector-curvature="0"
id="path5301"
d="M 15.577993,1039.1732 4.7040093,1028.3079 15.469253,1017.5512"
style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path5303"
d="m 4.921489,1028.3622 26.53252,0"
style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

64
flake-report/file.svg Normal file
View File

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="32"
height="48"
viewBox="0 0 32 48"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="file.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#3d3d3d"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="1"
inkscape:cx="24.812518"
inkscape:cy="18.901073"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
width="32px"
inkscape:window-width="1535"
inkscape:window-height="876"
inkscape:window-x="65"
inkscape:window-y="24"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-1004.3622)">
<path
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 4.1360619,1007.3622 0,34.375 23.7278761,0 0,-29.9038 -4.471158,-4.4712 -19.2567181,0 z m 18.5469091,0.6084 4.471159,4.4712 -4.471159,0 0,-4.4712 z m -16.6202866,7.8079 19.8746316,0 0,1.8252 -19.8746316,0 0,-1.8252 z m 0,3.2448 19.8746316,0 0,1.8253 -19.8746316,0 0,-1.8253 z m 0,6.0841 19.8746316,0 0,1.8252 -19.8746316,0 0,-1.8252 z m 0,8.2135 19.8746316,0 0,1.8252 -19.8746316,0 0,-1.8252 z"
id="path4749"
inkscape:connector-curvature="0" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

30
flake-report/index.html Normal file
View File

@ -0,0 +1,30 @@
<!DOCTYPE html>
<html>
<head>
<title>flake8 violations</title>
<meta http-equiv="Content-Type" value="text/html; charset=UTF-8">
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div id="masthead" class="sev-4"></div>
<div id="page">
<h1>flake8 violations</h1>
<p id="versions">Generated on 2025-02-14 11:49
with Installed plugins: flake8-html: 0.4.3, mccabe: 0.7.0, pycodestyle: 2.12.1, pyflakes: 3.2.0
</p>
<ul id="index">
<li>
<div id="all-good">
<span class="count sev-4">
<span class="tick">&#x2713;</span>
</span>
<h2>All good!</h2>
<p>No flake8 errors found in 8 files scanned.</p>
</div>
</li>
</ul>
</div>
</body>
</html>

327
flake-report/styles.css Normal file
View File

@ -0,0 +1,327 @@
html {
font-family: sans-serif;
font-size: 90%;
}
#masthead {
position: fixed;
left: 0;
top: 0;
right: 0;
height: 40%;
}
h1, h2 {
font-family: sans-serif;
font-weight: normal;
}
h1 {
color: white;
font-size: 36px;
margin-top: 1em;
}
h1 img {
margin-right: 0.3em;
}
h2 {
margin-top: 0;
}
h1 a {
color: white;
}
#versions {
color: rgba(255, 255, 255, 0.7);
}
#page {
position: relative;
max-width: 960px;
margin: 0 auto;
}
#index {
background-color: white;
box-shadow: 0 0 4px rgba(0, 0, 0, 0.8);
padding: 0;
margin: 0;
}
#index li {
list-style: none;
margin: 0;
padding: 1px 0;
}
#index li + li {
border-top: solid silver 1px;
}
.details p {
margin-left: 3em;
color: #888;
}
#index a {
display: block;
padding: 0.8em 1em;
cursor: pointer;
}
#index #all-good {
padding: 1.4em 1em 0.8em;
}
#all-good .count .tick {
font-size: 2em;
}
#all-good .count {
float: left;
}
#all-good h2,
#all-good p {
margin-left: 50px;
}
#index a:hover {
background-color: #eee;
}
.count {
display: inline-block;
border-radius: 50%;
text-align: center;
width: 2.5em;
line-height: 2.5em;
height: 2.5em;
color: white;
margin-right: 1em;
}
.sev-1 {
background-color: #a00;
}
.sev-2 {
background-color: #b80;
}
.sev-3 {
background-color: #28c;
}
.sev-4 {
background-color: #383;
}
a {
text-decoration: none;
}
#doc {
background-color: white;
margin: 1em 0;
padding: 1em;
padding-left: 1.2em;
position: relative;
box-shadow: 0 0 4px rgba(0, 0, 0, 0.8);
}
#doc pre {
margin: 0;
padding: 0.07em;
}
.violations {
position: absolute;
margin: 1.2em 0 0 3em;
padding: 0.5em 1em;
font-size: 14px;
background-color: white;
box-shadow: 0 0 4px rgba(0, 0, 0, 0.4);
display: none;
}
.violations .count {
font-size: 70%;
}
.violations li {
padding: 0.1em 0.3em;
list-style: none;
}
.line-violations::before {
display: block;
content: "";
position: absolute;
left: -1em;
width: 14px;
height: 14px;
border-radius: 50%;
background-color: red;
}
.code:hover .violations {
display: block;
}
tt {
white-space: pre-wrap;
font-family: Consolas, monospace;
font-size: 10pt;
}
tt i {
color: silver;
display: inline-block;
text-align: right;
width: 3em;
box-sizing: border-box;
height: 100%;
border-right: solid #eee 1px;
padding-right: 0.2em;
}
.le {
background-color: #ffe8e8;
cursor: pointer;
}
.le:hover {
background-color: #fcc;
}
.details {
clear: both;
}
#index .details {
border-top-style: none;
margin: 1em;
}
ul.details {
margin-left: 0;
padding-left: 0;
}
#index .details li {
list-style: none;
border-top-style: none;
margin: 0.3em 0;
padding: 0;
}
#srclink {
float: right;
font-size: 36px;
margin: 0;
}
#srclink a {
color: white;
}
#index .details a {
padding: 0;
color: inherit;
}
.le {
background-color: #ffe8e8;
cursor: pointer;
}
.le.sev-1 {
background-color: #f88;
}
.le.sev-2 {
background-color: #fda;
}
.le.sev-3 {
background-color: #adf;
}
img {
height: 1.2em;
vertical-align: -0.35em;
}
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.hll { background-color: #ffffcc }
.c { color: #3D7B7B; font-style: italic } /* Comment */
.err { border: 1px solid #F00 } /* Error */
.k { color: #008000; font-weight: bold } /* Keyword */
.o { color: #666 } /* Operator */
.ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */
.cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */
.cp { color: #9C6500 } /* Comment.Preproc */
.cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */
.c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */
.cs { color: #3D7B7B; font-style: italic } /* Comment.Special */
.gd { color: #A00000 } /* Generic.Deleted */
.ge { font-style: italic } /* Generic.Emph */
.ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.gr { color: #E40000 } /* Generic.Error */
.gh { color: #000080; font-weight: bold } /* Generic.Heading */
.gi { color: #008400 } /* Generic.Inserted */
.go { color: #717171 } /* Generic.Output */
.gp { color: #000080; font-weight: bold } /* Generic.Prompt */
.gs { font-weight: bold } /* Generic.Strong */
.gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.gt { color: #04D } /* Generic.Traceback */
.kc { color: #008000; font-weight: bold } /* Keyword.Constant */
.kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
.kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
.kp { color: #008000 } /* Keyword.Pseudo */
.kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
.kt { color: #B00040 } /* Keyword.Type */
.m { color: #666 } /* Literal.Number */
.s { color: #BA2121 } /* Literal.String */
.na { color: #687822 } /* Name.Attribute */
.nb { color: #008000 } /* Name.Builtin */
.nc { color: #00F; font-weight: bold } /* Name.Class */
.no { color: #800 } /* Name.Constant */
.nd { color: #A2F } /* Name.Decorator */
.ni { color: #717171; font-weight: bold } /* Name.Entity */
.ne { color: #CB3F38; font-weight: bold } /* Name.Exception */
.nf { color: #00F } /* Name.Function */
.nl { color: #767600 } /* Name.Label */
.nn { color: #00F; font-weight: bold } /* Name.Namespace */
.nt { color: #008000; font-weight: bold } /* Name.Tag */
.nv { color: #19177C } /* Name.Variable */
.ow { color: #A2F; font-weight: bold } /* Operator.Word */
.w { color: #BBB } /* Text.Whitespace */
.mb { color: #666 } /* Literal.Number.Bin */
.mf { color: #666 } /* Literal.Number.Float */
.mh { color: #666 } /* Literal.Number.Hex */
.mi { color: #666 } /* Literal.Number.Integer */
.mo { color: #666 } /* Literal.Number.Oct */
.sa { color: #BA2121 } /* Literal.String.Affix */
.sb { color: #BA2121 } /* Literal.String.Backtick */
.sc { color: #BA2121 } /* Literal.String.Char */
.dl { color: #BA2121 } /* Literal.String.Delimiter */
.sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
.s2 { color: #BA2121 } /* Literal.String.Double */
.se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */
.sh { color: #BA2121 } /* Literal.String.Heredoc */
.si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */
.sx { color: #008000 } /* Literal.String.Other */
.sr { color: #A45A77 } /* Literal.String.Regex */
.s1 { color: #BA2121 } /* Literal.String.Single */
.ss { color: #19177C } /* Literal.String.Symbol */
.bp { color: #008000 } /* Name.Builtin.Pseudo */
.fm { color: #00F } /* Name.Function.Magic */
.vc { color: #19177C } /* Name.Variable.Class */
.vg { color: #19177C } /* Name.Variable.Global */
.vi { color: #19177C } /* Name.Variable.Instance */
.vm { color: #19177C } /* Name.Variable.Magic */
.il { color: #666 } /* Literal.Number.Integer.Long */

20
main.py
View File

@ -1,17 +1,21 @@
from controllers.base import Controller from models.models import Tournament
from controllers.base import Application, Save
from views.base import View from views.base import View
from views.menu import Menu
def main(): def main():
tournament = Tournament()
view = View() view = View()
menu = Controller(view) save = Save(view)
menu.run() menu = Menu()
application = Application(tournament=tournament,
save=save,
view=view,
menu=menu)
# launch application
application.menu_manager()
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@ -1,27 +0,0 @@
from models.player import Player
class Match:
"""Get two players
print a string with both ids
return a tuple of list player, score
"""
def __init__(self, player1, player2):
self.name = None
self.player1 = player1
self.player2 = player2
self.score1 = 0
self.score2 = 0
self.data = ([self.player1, self.score1], [self.player2, self.score2])
def __str__(self):
return f"[{self.player1}, {self.player2}]" #pretty print for prompt
def __repr__(self):
#return ([self.player1, self.score1], [self.player2, self.score2])
return str(self)
def update(self):
"""Update tuple when attributs have change"""
self.data = ([self.player1, self.score1], [self.player2, self.score2])
return self.data

151
models/models.py Normal file
View File

@ -0,0 +1,151 @@
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.scores = []
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,
'score': self.score
}
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

View File

@ -1,46 +0,0 @@
from collections import UserDict
import json
from models.player import Player
class Participants(UserDict):
"""Dict of players and score attending a tournament
takes tournament's name and list of object Player
returns dict with player: score"""
def __init__(self, player_list): #player_list FOR TEST ; to feed when creating object
#self.tournament
self.player_list = player_list
self.data = {}
self.PLAYERS_FILE = "./data/players/player_list.json" #FOR TEST
def create_participant_from_list(self, players):
for item in players:
self.data[item.chess_id] = 0
return self.data
def get_list_from_file(self):
with open(self.PLAYERS_FILE) as file:
self.data = json.load(file)
def get_players_from_file(self):
"""create a Player list from the json file
uses file in current folder
return a list of object Player
"""
players = []
data = {}
with open(self.PLAYERS_FILE) as file:
data = json.load(file)
for i in data:
players.append(
Player(name=data[i][0], lastname=data[i][1], birthdate=data[i][2], gender=data[i][3], chess_id=i))
# print(data[i][0])
j = + 1
return self.create_participant_from_list(players)
def ask_for_new_participant(self):
pass

View File

@ -1,20 +0,0 @@
import json
from datetime import datetime
class Player:
"""Player from the club"""
def __init__(self, name, lastname, birthdate, gender, chess_id=None):
self.name = name
self.lastname = lastname
self.birthdate = birthdate
self.gender = gender
self.chess_id = chess_id
def __str__(self):
"""Used in print"""
# return f"{self.name} {self.lastname}, né le {self.birthdate}, genre: {self.gender}"
return self.chess_id
def __repr__(self):
return str(self)

View File

@ -1,28 +0,0 @@
from models.participant import Participants
from models.turn import Turn
class Tournament:
"""A competition with players and turns
takes player_list
"""
def __init__(self,
name,
participants,
location = "Club",
date_start = "today",
date_end = 'today',
current_turn = 1,
total_turn = 4 ):
self.name = name
self.participants = participants
self.location = location
self.date_start = date_start
self.date_end = date_end
self.total_turn = total_turn
self.current_turn = current_turn
self.description = "Pas encore de description"
self.turn_list = []

View File

@ -1,64 +0,0 @@
from random import choice, shuffle
from models.participant import Participants
from models.match import Match
class Turn:
"""Round for tournament
has name, dict of participant (object)
"""
def __init__(self, participants, name="Round 1"):
self.name = name
self.participants = participants
self.match_history = []
self.match_list = []
self.match_result = []
self.player_list = []
def ramble_player_list(self):
"""shuffle player's list"""
return shuffle(self.player_list)
def sort_players_by_score(self):
"""orders dict on value and returns sorted list"""
return sorted(self.participants.items(), key=lambda t: t[1])
def create_match(self):
print("Liste des joueurs: ", self.player_list)
j = 0
k = 0
for i in range(0, len(self.player_list), 2):
j += 1
match = Match(self.player_list[i][0], self.player_list[i+1][0])
match.name = "match" + str(j)
while match in self.match_history:
k += 1# If match has already been made, choose the next player
match = Match(self.player_list[i][0], self.player_list[i+k][0])
self.match_list.append(match)
else:
self.match_list.append(match)
#print(match)
self.match_history.append([self.name, self.match_list])
return self.match_list
# if i.index
def input_scores(self):
for match in self.match_list:
print(match.name)
self.result = input(f"Vainqueur du {match.name} : 1.{match.player1}, 2.{match.player2}, 3.nul\n ? ")
if self.result == "1":
self.participants[match.player1] += 1
match.score1 += 1
if self.result == "2":
self.participants[match.player2] += 1
match.score2 += 1
if self.result == "3":
self.participants[match.player1] += 0.5
match.score1 += 0.5
self.participants[match.player2] += 0.5
match.score2 += 0.5
match.update() # update match then save it at the end of the turn
self.match_result.append(match.data)
return self.match_result

View File

@ -1 +0,0 @@
{"EF34924": ["Bob", "Durand", "25/12/1995", "M"], "QS42622": ["Joe", "Bidjoba", "02/01/2001", "M"], "AB20022": ["Jeanine", "Mequesurton", "25/12/1995", "F"], "JF78739": ["Jean-Pierre", "Quiroul", "15/09/1992", "M"], "ED22230": ["Ren\u00e9", "Nuphard", "25/12/1995", "M"], "EE49948": ["Sophie", "Fonfec", "24/05/1999", "F"]}

View File

@ -1,10 +0,0 @@
{
"lastname": "Prout",
"name": "Joe",
"birth_date": "23/02/2003"
}
{
"lastname": "Dupont",
"name": "Pierre",
"birth_date": "20/01/2002"
}

View File

View File

@ -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()

View File

@ -1,12 +1,173 @@
from datetime import datetime
import re
class View: class View:
"""Prompt menu, get choices""" """Prompt menu, get choices"""
def __init__(self): def __init__(self):
pass 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): def prompt_for_scores(self):
print() print()
input("Saisir les scores ?") input("Saisir les scores ? (y)")
return True return True
def display_winner(self, participants): def prompt_next(self):
pass print()
input("?")
return True
def prompt_for_round(self, round):
print()
input(f"Prêt à lancer le {round.name} ? (y)")
return True
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 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 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_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 display_players(self, player_list_to_display):
print("\nListe des joueurs :")
for player in player_list_to_display:
print(f"{player.name} {str.upper(player.lastname)} ({player.ine})")
def display_tournaments(self, tournament_list_to_display):
print("\nListe des tournois : ")
for tournament in tournament_list_to_display:
print("-", tournament,
"le",
tournament_list_to_display[tournament]['start'])
def display_tournament_detail(self, tournament_to_display):
i = tournament_to_display
print("\n***************************************************")
print("\nNom du tournoi : ", i['name'])
print("Lieu : ", i['location'])
print("Description : ", i['description'])
print("Le tournoi a débuté le : ", i['start'])
print("Et s'est terminé le : ", i['end'])
print("\nLes participants étaient : ")
for j in i['players']:
print(j['ine'], "-", j['prénom'], str.upper(j['nom']))
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()
print("Les scores finaux :")
for j in i['players']:
print(j['prénom'], str.upper(j['nom']), ":", j['score'])
print("\n***************************************************")
def display_error(self):
print("Erreur de saisie, recommencez;")
def display_format_error(self):
print("\n**** Erreur de format de fichier")
def display_file_error(self, file):
print(f"\n**** Pas de fichier {file} trouvé :/")
def display_player_instructions(self):
print("Placez un fichier joueur dans le répertoire data "
"ou créez des nouveaux joueurs depuis le menu")
print()
def display_quit(self):
print("Bye !")
def display_error_already(self):
print("Déjà joué")
def ok_player(self):
print("\nJoueur créé.")
def ok_go(self):
print("\n!!! C'est parti !!!\n")
def ok_done(self, name):
print(f"\nLe tournoi {name} est terminé !\n")

View File

@ -11,23 +11,28 @@ class Menu:
"[1] Afficher la liste des joueurs", "[1] Afficher la liste des joueurs",
"[2] Afficher l'historique des tournois", "[2] Afficher l'historique des tournois",
"[3] Afficher le détail d'un tournoi", "[3] Afficher le détail d'un tournoi",
"[4] Quitter" "[4] Retour"
] ]
def items(self, value): def items(self, value):
"""displays menu depending on given value"""
menu_type = [] menu_type = []
if value == 1: if value == 1:
menu_type = self.ITEMS menu_type = self.ITEMS
print()
print("MENU GENERAL")
if value == 2: if value == 2:
menu_type = self.RAPPORTS menu_type = self.RAPPORTS
print()
print("MENU RAPPORTS")
for i in menu_type: for i in menu_type:
print(i) print(i)
while True:
try: try:
demande = input("Choix ? : ") choice = input("Choix ? : ")
if demande not in range(1, len(menu_type)): if int(choice) not in range(1, len(menu_type) + 1):
demande = input("Choix ? : ") print("Choisissez un chiffre entre 1 et", len(menu_type))
else:
return choice
except ValueError: except ValueError:
print("Veuillez saisir un chiffre") print("Veuillez entrer un chiffre")
demande = input("Choix ? : ")
return demande

165
vrac.py
View File

@ -1,165 +0,0 @@
from models.participant import Participants
from models.player import Player
from models.match import Match
from models.turn import Turn
from models.tournament import Tournament
from views.base import View
from random import randint
import json
# generate player list
def generate_liste():
liste = []
for i in range(16):
liste.append(["Player"+str(i+1), randint(0, 8)])
return liste
def create_player_list_file(player_list):
"""create a JSON file using a Player list
takes a list of object Player
returns nothing but write file"""
player_dict = {}
for i in player_list:
player_dict[i.chess_id] = [i.name, i.lastname, i.birthdate, i.gender]
# print(player_dict)
with open("player_list.json", "a") as file:
json.dump(player_dict, file)
print("done.")
def get_list_from_file():
"""create a Player list from the json file
uses file in current folder
return a list of object Player
"""
players = []
data = {}
with open("player_list.json") as file:
data = json.load(file)
for i in data:
players.append(Player(name = data[i][0], lastname = data[i][1], birthdate = data[i][2], gender = data[i][3], chess_id = i))
#print(data[i][0])
j =+ 1
return players
# joueur'data.index[i]' = Player(name = i)
def chess_id_from_name(name, player_list):
for i in player_list:
if str(name) == str(i.name + " " + i.lastname):
return i.chess_id
return None
def name_from_chess_id(chess_id, player_list):
for i in player_list:
if str(chess_id) == str(i.chess_id):
return str(i.name + " " + i.lastname)
return None
joueur1 = Player("Bob", "Durand", "25/12/1995", "M", "EF34924")
joueur2 = Player("Joe", "Bidjoba", "02/01/2001", "M", "QS42622")
joueur3 = Player("Jeanine", "Mequesurton", "25/12/1995", "F", "AB20022")
joueur4 = Player("Jean-Pierre", "Quiroul", "15/09/1992", "M", "JF78739")
joueur5 = Player("René", "Nuphard", "25/12/1995", "M", "ED22230")
joueur6 = Player("Sophie", "Fonfec", "24/05/1999", "F", "EE49948")
player_list = [joueur1, joueur2, joueur3, joueur4, joueur5, joueur6]
#create_player_list_file(player_list)
#print("la player_list from file : ", get_list_from_file())
#print("La player_list crée dans le script : ", player_list)
# print(liste_from_file)
#print(chess_id_from_name("Joe Bidjoba", player_list))
#print(name_from_chess_id("JF78739", player_list))
def test2(player_list):
# create new participants object (dict from list)...
participants = Participants("Tournoi de cajou", player_list)
# display the dict
print("print(participants) : ", participants.create_participant_from_list())
print(participants.data)
tour1 = Turn(participants.data)
print(tour1.create_match())
tour1.input_scores()
print(participants)
def test(player_list):
participants = Participant("Tournoi de cajou", player_list)
print("print(participants) : ", participants.create_participant_from_list())
print("Le score de ('Joe', 'Bidjoba') : ", participants.get((chess_id_from_name("Joe Bidjoba", player_list))))
match = Match(joueur1, joueur3)
print("print(match): ", match)
match.score2=1
print("print(match), après match.score2=1: ", match)
turn1 = Turn(participants, "Round 1")
turn1.create_player_list()
print("turn1.player_list : ",turn1.player_list)
turn1.ramble_player_list()
turn1.create_matches()
print("turn1.match_list : ", turn1.match_list )
turn1.input_scores()
print("print(participants) : ", participants)
def test3():
# initialization
participants = Participants(player_list)
participants.get_players_from_file() #load dict from file
view = View()
turn_nb = 1
tournoi1 = Tournament("Tournoi de Cajou", participants)
def run_turn(turn_nb):
tour = Turn(participants.data, name = "Round"+str(turn_nb))
print("Commençons le", tour.name)
if turn_nb == 1:
tour.player_list = tour.sort_players_by_score()
else:
tour.player_list = tour.sort_players_by_score()
tour.create_match()
print(f"La liste des matchs pour le {tour.name} est :\n {tour.match_list}")
view.prompt_for_scores()
tour.input_scores()
print("Save \n", tour.name, tour.match_result)
tournoi1.turn_list.append([tour.name, tour.match_result])
def display_winner(participants):
base =
for i in participants:
if participants[i]
print("Début du", tournoi1.name, "!")
while turn_nb < tournoi1.total_turn:
tournoi1.current_turn = turn_nb
run_turn(turn_nb)
turn_nb += 1
print("\nLe", tournoi1.name, "est terminé.\n")
print("Scores finaux:\n", participants.data)
print("liste des tours:\n", tournoi1.turn_list)
#for i in range(1, tournoi1.total_turn+1):
#tour = Turn(participants, name = "Round"+str(i))
#tour.
test3()