Un jeu de carte
Description du projet¶
Ce projet de difficulté intermédiaire se donne pour but de modéliser un jeu de carte à l'aide de Python. Dans un premier temps, on construit deux classes, Carte
et Deck
afin de représenter un jeu classique de 52 cartes. Puis, on implémente deux classes, Joueur
et Bataille
. Celles-ci nous permettent alors de faire jouer l'ordinateur à la bataille contre lui-même ou bien contre un joueur humain. N'oubliez pas d'importer la fonction randint
.
1 |
|
La classe Carte
¶
Une carte d'un jeu de 52 cartes possède une valeur qui est un nombre entier compris entre \(2\) et \(14\), et une couleur parmi "pique", "carreau", "cœur", "trèfle". Par convention, la carte dont la valeur est la plus élevée est l'as, associé à la valeur 14. On prendra dans ce projet la convention que la figure la plus forte est la Dame (associée à la valeur 13), puis le Roi (associé à la valeur 12), puis le valet (associé à la valeur 11). On pourra au choix prendre la convention du Roi maître à la couleur, mais ceci n'est pas obligatoire.
Étant donné une carte, on souhaite pouvoir l'afficher (par exemple "Dame de cœur"), et pouvoir la comparer à une autre carte (par exemple, "Reine de cœur bat roi de cœur", mais il y a égalité entre "Reine de cœur" et "Reine de pique").
- Quelles sont les données décrivant un objet de type
Carte
? - Pour chacunes des deux données précédentes, préciser quel type python permet de les représenter au mieux.
- Déduire des questions précédentes le code python d'une classe
Carte
. On n'indiquera pour le moment que la méthode__init__
de cette classe. - D'après l'énoncé, quels sont les actions que l'on souhaite effectuer sur des cartes ?
1 2 |
|
Méthodes de la classe¶
Méthode __str__
¶
Écrire la méthode spéciale __str__
de la classe carte. Celle-ci s'applique à un objet de type Carte
et en renvoie une représentation textuelle. Par exemple, si la variable c
représente la carte "Dame de cœur", print(c)
devra afficher "Dame de cœur". On pourra au choix tester l'attribut valeur
d'une carte et renvoyer le nom de la figure correspondante ("Roi" pour 12 par exemple) à l'aide branchements conditionnels if/elif/else
. Pour simplifire le code, on pourra utiliser de manière astucieuse un dictionnaire, dont les clés sont seront les valeurs possibles pour l'attribut valeur
et les valeurs le texte correspondant.
1 2 3 4 |
|
Méthode bat
¶
Écrire une méthode bat
de la classe Carte
qui étant donné deux cartes self
et other
, renvoie True
si self
bat other
, et False
sinon. Si jamais les deux cartes ont la même valeur, alors bat
renverra la valeur spéciale None
.
1 2 3 4 |
|
La classe Deck
¶
Dans ce projet, un paquet de carte est constitué des 52 différentes cartes possibles. Ainsi, une variable de type Deck
n'aura qu'un seul attribut, contenu
. Celui-ci sera une liste de cartes. Lors de l'initialisation, on ajoutera automatiquement les 52 cartes au deck, dans l'ordre de votre choix.
Lorsque l'on manipule un deck, les actions principales à supporter sont de le mélanger, et de tirer une carte du deck. On peut éventuellement vouloir compter les cartes du deck, afin de savoir s'il est encore possible d'en tirer.
1 2 |
|
Les méthodes de la classe Deck
¶
Méthode tirer
¶
Écrire une méthode tirer
de la classe Deck
qui renvoie la première carte du paquet. On pourra éventuellement utiliser un argument optionnel pour choisir l'indice de la carte tirée dans le deck. S'il n'est pas possible de tirer une carte du deck, alors on renverra la valeur spéciale None
. Attention, après l'exécution de d.tirer()
, l'attribut contenu
du deck d
doit avoir été modifié de telle sorte que la carte tirée ne s'y trouve plus.
1 2 3 4 |
|
Méthode melanger
¶
Écrire une méthode melanger
de la classe Deck
. Étant donné un deck self
, celle-ci permute aléatoirement les éléments de la liste self.contenu
. Plusieurs algorithmes sont pour cela possibles :
- si
n = len(self.contenu)
, alors on peut tirer successivementn
cartes du deck (en choisissant leurs indices aléatoirement) et les placer dans uneliste
de cartes temporaire (à l'aide de la méthodeappend
). Puis, on mettra a jour l'attributcontenu
deself
. - il est possible de mélanger directement une liste à l'aide du module
random
.
1 2 3 4 |
|
Méthode __len__
¶
Écrire une méthode spéciale __len__
de la classe Deck
. Celle-ci renverra la taille de l'attribut contenu
de l'objet self
. Une fois cette méthode implémentée, l'intruction len(d)
est équivalente à d.__len__()
.
1 2 3 4 |
|
Méthode __str__
¶
Écrire une méthode __str__
de la classe Deck
qui permet d'afficher toutes les cartes d'un deck. On concatènera le résultat de carte.__str__()
pour toutes les carte
du deck.
Remarque. On pourra utiliser la chaine de caractère "\n"
pour représenter les retours à la ligne entre l'affichage de deux cartes.
1 2 3 4 |
|
La classe Joueur
¶
Les joueurs ont tous un nom
, et possèdent dans leur main
un tas de carte (une liste de Carte
). Initiallement, un joueur ne possède aucune carte dans sa main
. Chaque joueur doit pouvoir piocher une carte du deck central, joueur une carte sur le tapis, et ramasser un tas de carte qui se trouve sur le tapis (il peut y en avoir plus de deux en cas de bataille, par exemple).
Remarque. Il est possible d'utiliser un objet de type Deck
pour l'attribut main
, et d'implémenter directement certaines fonctionnalités dans la classe Deck
. Cependant, inutile ici de faire très compliqué, une simple liste suffit.
1 2 |
|
Méthodes de la classe Joueur
¶
Méthode piocher_carte
¶
Écrire une méthode piocher_carte
de la classe Joueur
qui étant donné un joueur self
et un deck
, simule la pioche d'une carte du deck
par le joueur
. Pour cela, on tire une carte du deck, puis on l'ajoute à la main. Les cartes piochées sont empilées les unes sur les autres, par convention la dernière carte piochée correspondra donc à l'indice le plus élevé dans main
. En python, le dernier élément d'un tableau non vide a pour indice -1
.
1 2 3 4 |
|
Méthode jouer_carte
¶
Écrire une méthode jouer_carte
de la classe Joueur
qui simule l'action de déposer une carte au centre de la table. Le joueur self
retire la première carte de son paquet et la renvoie. À l'issue de l'exécution de cette méthode, il y a une carte de moins dans self.main
.
1 2 3 4 |
|
Méthode ramasser
¶
Écrire une méthode ramasser
de la classe Joueur
qui étant donné un joueur self
et une pile
de cartes place toutes les cartes de la pile
en dessous de la main du joueur. À l'issue de l'exécution de la méthode ramasser
, la pile
sera vide et la main
du joueur aura augmenté d'autant de cartes. On pourra utiliser la méthode insert
du type python list
(il y a d'autres méthodes, avec la concaténation de listes par exemple).
1 2 3 4 |
|
Une partie ? La classe Bataille
¶
Le jeu de la bataille fait s'affronter deux joueurs à l'aide d'un deck
(mélangé, de préférence) : un joueur1
et un joueur2
. Après la phase de distribution des cartes du deck, les joueurs jouent alternativement leurs cartes sur une pile
centrale, initialement vide.
On pourra au choix implémenter une ou plusieurs des méthodes suivantes de la classe Bataille
. Vous écrirez pour chacunes des méthodes des tests qui permettent de s'assurer de leur bon fonctionnement. Si vous ne parvenez pas au comportement souhaité, vous devez expliquer votre démarche et indiquer votre code défaillant.
- une méthode
distribuer
: distribue ledeck
aux deux joueurs, en alternant une carte à l'un, une carte à l'autre. - une méthode
jouer_tour
: simule un tour de bataille. Les deux joueurs jouent une carte sur lapile
centrale, puis, la plus forte des cartes l'emporte. Si jamais les deux cartes sont de même valeur, alors il y a bataille ! Chaque joueur dépose une carte sur la pile centrale, puis on recommence un tour. Il sera possible d'utiliser un appel récursif à la méthodejouer_tour
. - une méthode
fin_partie
: on vérifie si la bataille est terminée ou non. Plusieurs cas peuvent survenir :- soit un des deux joueurs n'a plus de cartes dans sa main, dans ce cas c'est l'autre joueur qui est déclaré gagnant ;
- soit un joueur ne peut pas déposer une carte alors qu'il doit en déposer une (cela peut arriver lors d'une bataille, par exemple). Dans ce cas c'est l'autre joueur qui est déclaré gagnant.
- une méthode
run
: on joue les tours les uns après les autres tant que la partie n'est pas terminée. Une fois que la partie est terminée, on renvoie le joueur gagnant. On pourra limiter le nombre maximum de coups à 1000 pour éviter les batailles trop longues.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|