Projet : Amélioration des objets cartes
Nous allons améliorer la classé que nous avions crée lors du projet précédent (en prérequis).
Un code possible d'une carte
Un code possible d'une carte
Fichier carte.py :
SEPT = 7
HUIT = 8
NEUF = 9
DIX = 10
VALET = 11
DAME = 12
ROI = 13
AS = 14
PIQUE = 4
COEUR = 3
CARREAU = 2
TREFLE = 1
VALEURS = (SEPT, HUIT, NEUF, DIX, VALET, DAME, ROI, AS)
COULEURS = (TREFLE, CARREAU, COEUR, PIQUE)
class Carte:
def __init__(self, valeur, couleur):
self.couleur = couleur
self.valeur = valeur
def texte(self):
valeur = ["7", "8", "9", "10", "V", "D", "R", "1"]
couleur = ["♣︎", "♦", "♥", "♠"]
return valeur[self.valeur - 7] + couleur[self.couleur - 1]
def plus_grande_ou_égale_que(self, other):
return (self.valeur > other.valeur) or (
(self.valeur == other.valeur) and (self.couleur >= other.couleur)
)
Fichier test_carte.py :
import carte
from carte import Carte
def test_constructeur():
assert isinstance(Carte(carte.SEPT, carte.TREFLE), Carte)
def test_texte():
assert Carte(carte.SEPT, carte.TREFLE).texte() == "7♣︎"
def test_plus_grande_ou_égale_que():
assert Carte(carte.AS, carte.TREFLE).plus_grande_ou_égale_que(Carte(carte.VALET, carte.PIQUE))
assert Carte(carte.AS, carte.TREFLE).plus_grande_ou_égale_que(Carte(carte.AS, carte.TREFLE))
assert Carte(carte.AS, carte.PIQUE).plus_grande_ou_égale_que(Carte(carte.AS, carte.TREFLE))
assert not Carte(carte.VALET, carte.PIQUE).plus_grande_ou_égale_que(Carte(carte.AS, carte.TREFLE))
Affichage d'une carte
Remplacez la méthode Carte.texte() par la méthode Carte.__str__().
Modifiez les tests pour prendre en compte de cette nouvelle méthode.
Attribut de classes
Pour créer les cartes on utilise des constantes définies dans le fichier carte.py. Commençons par mettre ces constantes directement dans la classe pour ne pas avoir à tout importer :
Placez les différentes constantes relatives aux valeurs et aux couleur des cartes en attributs de classe et modifiez les tests en conséquence.
Cependant, pour spécifier à l'utilisateur les valeurs et couleurs possibles, utilisez des constantes et des tuples n'est cependant pas optimal. Pour gérer les énumérations, python met à disposition les Enum.
On pourrait ainsi gérer les couleurs ainsi :
>>> from enum import Enum
>>> couleur = Enum("Couleur", [("Pique", 4), ("Cœur", 3), ("Carreau", 2), ("Trèfle", 1)])
>>> print(couleur.Pique.name)
pique
>>> print(couleur.Pique.value)
4
>>> c = couleur.Pique
>>> print(c)
Couleur.Pique
>>> print(repr(c))
<Couleur.Pique: 4>
>>> for c in couleur:
... print(c)
...
Couleur.pique
Couleur.cœur
Couleur.carreau
Couleur.trèfle
Le but est de pouvoir utiliser nos énums directement comme dans l'exemple.
Remplacez les tests par le code suivant, qui utilise les Enum de python :
from carte import Carte
def test_constructeur():
assert isinstance(Carte(Carte.VALEURS.Sept, Carte.COULEURS.Trèfle), Carte)
def test_str():
assert str(Carte(Carte.VALEURS.Sept, Carte.COULEURS.Trèfle)) == "7♣︎"
# def test_plus_grande_ou_égale_que():
# assert Carte(carte.AS, carte.TREFLE).plus_grande_ou_égale_que(Carte(carte.VALET, carte.PIQUE))
# assert Carte(carte.AS, carte.TREFLE).plus_grande_ou_égale_que(Carte(carte.AS, carte.TREFLE))
# assert Carte(carte.AS, carte.PIQUE).plus_grande_ou_égale_que(Carte(carte.AS, carte.TREFLE))
# assert not Carte(carte.VALET, carte.PIQUE).plus_grande_ou_égale_que(Carte(carte.AS, carte.TREFLE))
Utiliser les Enum va pour l'instant casser notre méthode plus_grande_ou_égale_que, on commente donc pour l'instant le test.
À vous de modifier le constructeur et la méthode __str__() pour que les tests passent :
- Utilisez des
Enumpour gérer les constantes de classesVALEURSetCOULEURS, puis supprimez les constantes relatives aux différentes valeurs et couleurs individuelles (on n'utilisera que les enum et leur valeur associée). - Pour le code de la méthode
__str__(), vous pourrez utiliser l'attributvalued'unEnumpour faire le bon choix de représentation textuelle.
Cette technique est redoutable : elle est à la fois lisible, sans magic number et portable ! Utilisez-la dès que vous voulez gérer des énumérations.
Profitez de cette restructuration du code pour implémentez la méthode spéciale __repr__ et testez là en utilisant la fonction repr :
def test_repr():
assert repr(Carte(Carte.VALEURS.Sept, Carte.COULEURS.Trèfle)) == "Carte(Carte.VALEURS.Sept, Carte.COULEURS.Trèfle)"
Comparaisons
Une fois la carte créée, il ne faudrait plus pouvoir la modifier. Or pour l'instant on a directement accès aux attributs, donc rien n'interdit de le faire, rendons nos attributs privés :
Rendez les attributs valeurs et couleurs de chaque carte privé.
Méthode de conception
Lorsque l'on crée un objet, si on a pas de raison particulière de le rendre modifiable on crée un value object. Cela évite les effets de bords (et rend la programmation concurrente et parallèle bien plus simple).
Modification de la méthode plus_grande_ou_égale_que
Pour l'instant notre méthode plus_grande_ou_égale_que et son test ne fonctionnent pas avec les Enum. Corrigeons ça pour le test :
def test_plus_grande_ou_égale_que():
assert Carte(Carte.VALEURS.As, Carte.COULEURS.Trèfle).plus_grande_ou_égale_que(Carte(Carte.VALEURS.Valet, Carte.COULEURS.Pique))
assert Carte(Carte.VALEURS.As, Carte.COULEURS.Trèfle).plus_grande_ou_égale_que(Carte(Carte.VALEURS.As, Carte.COULEURS.Trèfle))
assert Carte(Carte.VALEURS.As, Carte.COULEURS.Pique).plus_grande_ou_égale_que(Carte(Carte.VALEURS.As, Carte.COULEURS.Trèfle))
assert not Carte(Carte.VALEURS.Valet, Carte.COULEURS.Pique).plus_grande_ou_égale_que(Carte(Carte.VALEURS.As, Carte.COULEURS.Trèfle))
À vous de changer son code :
Faites fonctionner la méthode plus_grande_ou_égale_que.
Comparaisons de cartes
Ajoutez à votre classe carte les opérateurs de comparaisons :
Codez et testez les opérateurs de comparaisons :
==qui correspond a à la méthode__eq__!=qui correspond a à la méthode__ne__<qui correspond a à la méthode__lt__>qui correspond a à la méthode__gt__<=qui correspond a à la méthode__le__>=qui correspond a à la méthode__ge__
N'hésitez pas à utiliser des opérateurs déjà codé. Vous pouvez par exemple utiliser les fonctions == et <= pour coder les autres les comparaisons.