Des dés !
L’objectif de cette activité est de réaliser, par toutes petites étapes un programme de jeu de dés …
Vous y apprendrez :
- à définir des classe à partir de diagrammes UML,
- définir des constructeurs avec différents usages des arguments,
- employer des mutateurs, des accesseurs et des attributs privés,
- utiliser des arguments de tailles variables,
- …
Simples classes
Les dés (classe
De
) du jeu (classe Jeu
) doivent être instanciés lors la construction du jeu.Exemple : Jeu(5, 6)
doit instancier (et mémoriser dans un attribut des
) 5 dés de 6 faces
Remarque : la relation entre les classes
Jeu
etDe
peut se lire : « Chaque objet de typeJeu
contient au moins 1 objet de typeDe
»Cela implique qu’il faudra définir dans la définition de la classe
Jeu
un attributdes
, de type liste d’objets de typeDe
.Cette définition apparaît pas dans le cadre de la classe, mais c’est redondant …
lancer
à la classe De
. Cette méthode doit retourner une valeur aléatoire comprise entre 1 et le nombre de faces du dé.Il est conseillé d’utiliser la fonction
randint
du module random
.
Mémorisation des valeurs
On souhaite à présent que les valeurs des dés du jeu restent mémorisées au sein même des objets, un peu comme si les dés du jeu étaient posés sur le plateau de jeu.
Les méthodes lancer()
deviennent de type « procédure » (elles ne renvoient rien !) mais la valeur de chaque dé est mémorisé au sein de chacun des objets dé, dans un nouvel attribut valeur
(un entier valant de 1
à nbr_faces
).
Dans certaines règles de jeu de dés, il est possible de faire plusieurs lancers, et parfois même de ne pas lancer tous les dés.
Jeu.lancer
en ajoutant un argument à mot clé exclure
de type liste contenant les indices (dans la liste des dés du jeu) des dés à ne pas lancer.
Affichage
__repr__
à la classes De
, afin d’afficher la valeur donnée par un lancer.Utiliser le caractère unicode
0x2680
et les suivants, en passant par la fonction chr
.Par exemple pour afficher la valeur 5 d’un dé de_1
, l’instruction print(de_1)
doit afficher ⚄ .
Le dé dans tous ses états
Lors du déroulement d’une partie (selon les règles du jeu), un dé peut prendre plusieurs états :
- pas encore lancé (dans la main d’un joueur)
- posé sur le plateau (avec une de ses faces visible)
- bloqué sur le plateau (avec une de ses faces visible) : il ne peut pas être relancé
Il faut convenir d’un « code » pour qualifier ces différents états. On peut, par exemple utiliser un seul attribut valeur
de la manière suivante :
- pas encore lancé :
valeur = 0
- posé sur le plateau :
valeur = 1
ànbr_faces
- bloqué sur le plateau :
valeur = -1
à-nbr_faces
(nombres négatifs)
Afin de pouvoir facilement changer cette manière de coder l’état d’un dé, et pour éviter d’avoir à modifier de nombreuses lignes de code, il est préférable de rendre l’attribut valeur
« privé » et de passer par des méthodes « publiques » pour obtenir l’état du dé :
Il faut bien entendu :
- interdire de lancer un dé bloqué (et donc interdire de modifier sa valeur avec
.set_valeur()
) - ne pas pouvoir bloquer un dé non encore posé
Afin de permettre aux objets qui utilisent des dés de savoir si une action a eu un effet (blocage, lancer, …) on décide de renvoyer un indicateur de « réussite » sous la forme d’un booléen :
True
: l’action a produit un effetFalse
: l’action n’a pas eu d’effet
De
.
Le jeu de dés
A présent, il faut permettre au programme de manipuler les dés au sein du jeu qui les contient. On enrichi donc la structure de la classe Jeu
:
Attention, les méthodes d’action (lancer, bloquer, …) doivent, à l’instar de celles des objets De
, renvoyer un indicateur de réussite (voir plus haut).
Remarque : le symbole
*
devant les paramètres des méthodes permet de pouvoir passer les arguments comme plusieurs valeurs et récupérer un tuple dans la méthode.exemple si on appelle
lancer(1,2)
, à l’intérieur de la méthode,num_des
sera le tuple(1,2)
.
Jeu
.
Analyse des résultats
On désire maintenant afficher le résultat d’une combinaison obtenue, après un ou plusieurs lancer, en accord avec les règles d’un jeu, par exemple celui du 421.
On décide de donner le résultat d’un jeu de dés grâce à deux valeurs, l’objectif étant de pouvoir classer toutes les combinaisons de manière absolue (pas de combinaisons ex-aequo) :
- le nombre de points : de 1 à 8 dans le jeu de 421
exemple : 114 = (4 points) > 333 (3points)
- la valeur de la combinaison :
exemple : 641 (1 point) > 533 (1 point)
Jeu
une méthode evaluer
renvoyant le nombre de points et la valeur de la combinaison du jeu.
Comparaison des combinaisons
En Python certains noms de méthode sont réservés à des usages particulier (nous avons vu le cas de la méthode __repr__
), mais il en existe de nombreuses autres :
objet1.__lt__(objet2)
renvoieTrue
siobjet1
est strictement inférieur (lt = less than) àobjet2
objet1.__eq__(objet2)
renvoieTrue
siobjet1
est égal (eq = equal) àobjet2
- …
Ces méthodes doivent impérativement renvoyer un booléen. Charge au programmeur de définir ce qui fait qu’un objet est plus petit, plus grand ou égal à un autre …
Une fois définis, il est possible de comparer deux objets en utilisant les opérateurs habituels :
par exemple : objet1.__lt__(objet2)
est équivalent à objet1 < objet2
!
__lt__
et __eq__
à la classe Jeu
.j1 = Jeu() j2 = Jeu() print(j1.lancer(0,1,2)) print(j2.lancer(0,1,2)) if j1 < j2: print(j1, "<", j2) elif j1 == j2: print(j2, "=", j1) else: print(j2, "<", j1)
Les joueurs
Maintenant que l’on sait classer les combinaisons obtenues, on peut envisager d’organiser une partie avec plusieurs joueurs.
Joueur
, qui pourra, en plus de caractéristiques générales (nom, …), posséder un attribut score
.
Et la partie de dés !
Il faut à présent définir la classe qui gérera la partie de dés.
Cette classe devra donc posséder:
- un jeu de dés
- des joueurs (2 ou plus)
C’est cette classe qui définira les règles du jeu (il faudra donc s’occuper de la méthode Jeu.evaluer
qui n’est pas à la bonne place.
Déroulement de la partie