Projet composition d'objets : dés
Dans le premier projets dés, vous avez codé des classes toutes seules. Dans cette parties on va coder plusieurs classes enchevêtrées.
Pour les besoins de ce projet, nous allons présupposer que vous avez une classe Dé
qui fonctionne. La version minimale que nous allons utiliser ici est disponible ci-après. Mais ne vous sentez pas obliger de l'utiliser.
une implémentation de la classe Dé
une implémentation de la classe Dé
fichier dé.py
:
import random
MIN_VALEUR = 1
MAX_VALEUR = 6
class Dé:
def __init__(self, position=1):
self._position = 1 # init
self.position = position # utilisation du mutateur
def lancer(self):
self.position = random.randrange(MIN_VALEUR, MAX_VALEUR + 1)
return self
fichier test_dé.py
:
from dé import Dé, MIN_VALEUR, MAX_VALEUR
def test_init():
assert type(Dé()) == Dé
def test_position():
assert Dé().position == 1
assert Dé(position=3).position == 3
def test_lancer():
assert MIN_VALEUR <= Dé().lancer().position <= MAX_VALEUR
Il va nous falloir manipuler 5 dés ensemble pour réaliser le but de notre projet :
But du projet
Jouer au poker d'as.
Nous n'atteindrons pas ce but à la fin du projet, mais libre à vous de le continuer et de le finir.
5 dés
Méthode naïve pour manipuler 5 dés : la liste de dés.
Pour illustrer cette étape et progresser dans notre projet de jeu, faisons une petite user story :
User Story
- Nom : "jets de dés"
- Utilisateur : un joueur compulsif
- Story : On veut pouvoir lancer des dés et voir le résultat
- Actions :
- créer une liste
- créer 5 dés que l'on ajoute un à un à la liste
- lancer les 5 dés
- afficher les valeurs des dés de la liste
Créez la user story dans le fichier story_jets.py
Composition
L'utilisation d'une liste permet de groper les 5 dés, mais il faut toujours les lancer individuellement. Cela pourrait être pratique de lancer automatiquement tous les dés.
Classe TapisVert
On aimerait avoir une structure, nommée TapisVert
, qui :
- crée et stocke 5 dés
- permette de lancer les dés stockés en une fois avec une méthode
lancer
- rendre les dés contenus dans sa structure via une liste ou un tuple
- Proposez une modélisation UML de cette classe, montrez la relation qu'elle entretien avec la classe
Dé
. - modifier la user story "jets de dés" pour qu'elle utilise cette classe
corrigé
corrigé
story_jets.py
:
from dé import TapisVert
tapis_vert = TapisVert()
tapis_vert.lancer()
for dé in tapis_vert.dés:
print(dé.position)
Avant de commencer à coder, comprenez comment il est possible que la méthode TapisVert.lancer()
peut utiliser la méthode Dé.lancer()
alors que les deux méthodes ont le même nom.
Maintenant que vous voyez comment faire codez là :
Ajoutez le code de la classe TapisVert
dans le fichier dé.py
.
Ajoutez les test de cette nouvelle classe au fichier test_dé.py
. Vous pourrez par exemple tester :
- qu'après la création d'un objet
TapisVert
on dispose bien de 5 dés positionnés sur 1. - qu'après avoir lancé les dés, leurs positions sont toujours cohérentes avec le nombre de faces.
- que
TapisVert
donne bien ses dés et non une copie de ceux-ci. Pour réaliser ceci vous pourrez implémenter le test suivant :- demander les dés d'un objet de type
TapisVert
- modifier la position d'un dé
- redemander les dés de l'objet de type
TapisVert
et vérifier que la position du dé est bien celle modifiée
- demander les dés d'un objet de type
Affichage
Afin de pouvoir coder plus rapidement nos story, il faut une méthode de représentation de nos objets.
Commençons par le Dé
:
Créez une méthode Dé.__str__
qui permettent d'écrire :
>>> from dé import Dé
>>> d = Dé()
>>> d.position = 4
>>> print(d)
⚃
>>>
Vous pourrez utilisez les caractères : "⚀"
, "⚁"
, "⚂"
, "⚃"
, "⚄"
et "⚅"
pour vos représentations.
On peut maintenant utiliser Dé.__str__
pour que TapisVert.__str__
soit facile à coder :
Créez une méthode TapisVert.__str__
qui permettent d'écrire :
>>> from dé import TapisVert
>>> tapis_vert = TapisVert()
>>> print(tapis_vert)
⚀ - ⚀ - ⚀ - ⚀ - ⚀
>>> tapis_vert.lancer()
>>> print(tapis_vert)
⚀ - ⚁ - ⚁ - ⚀ - ⚁
>>>
corrigé
corrigé
On peut utiliser deux trucs. Le premier est de construire une liste avec les représentations sous la forme d'une chaîne de caractères des dés. Par exemple :
>>> from dé import TapisVert
>>> tapis_vert = TapisVert()
>>>[str(x) for x in tapis_vert.dés]
['⚀', '⚀', '⚀', '⚀', '⚀']
Puis utiliser la méthode str.join
de python qui est super utile pour concaténer des listes de chaînes de caractères :
>>> l = ["coucou", "les", "amis"]
>>> "*".join(l)
'coucou*les*amis'
Ces deux astuces nous permettent d'écrire le code :
class TapisVert:
# ...
def __str__(self):
return " - ".join([str(x) for x in self.dés])
# ...
Reconnaissance
Pour jouer au poker d'as, il nous faudra reconnaître des formes de jets de dés (comme les paires, ou encore les full). Créons une user story pour coder cette fonctionnalité :
User Story
- Nom : "formes de jets"
- Utilisateur : un joueur compulsif
- Story : On veut pouvoir savoir quelles formes de dés sont présentes
- Actions :
- jeter 5 dés
- vérifier s'il y a une paire, un brelan ou un carré
- recommencer en 1
Créez la story dans le fichier story-formes-dés.py
.
Pour cela, l'utilisateur pourra appuyer sur la entrée pour lancer les dés d'un objet de type TapisVert
, afficher les 5 dés et indiquer s'il y a une paire, un brelan ou un carré avec des méthodes TapisVert.possède_paire()
, TapisVert.possède_brelan()
, et TapisVert.possède_carré()
qui rendent des booléens.
Et maintenant le code des différentes méthodes à implémenter :
Ajoutez dans TapisVert
les méthodes nécessaires et testez-les en simulant des lancez ayant une forme particulière.
Pour coder cela de façon simple, vous pourrez coder deux méthodes supports :
- une méthode qui rend une liste $L$ de taille 7 telle que $L[i]$ donne le nombre de dés ayant la position $i$ ($1 \leq i \leq 6$)
- une méthode qui prend en paramètre un nombre $n$ et qui rend
True
s'il existe au moins $n$ dés ayant la même position. Ceci permettra de coder de la même manières les différentes fonctions demandées.