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 successivementncartes du deck (en choisissant leurs indices aléatoirement) et les placer dans unelistede cartes temporaire (à l'aide de la méthodeappend). Puis, on mettra a jour l'attributcontenudeself. - 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 ledeckaux 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 lapilecentrale, 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 | |