449 lines
12 KiB
Markdown
449 lines
12 KiB
Markdown
|
|
# TP : Pokémon Arena — Programmation Orientée Objet
|
|||
|
|
|
|||
|
|
> **Thème** : Classes, attributs, méthodes, interactions entre objets
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Contexte
|
|||
|
|
|
|||
|
|
Depuis 1996, Pokémon est l'une des franchises les plus populaires au monde. En 2026, avec la sortie de Pokémon Legends: Z-A, la licence bat tous les records.
|
|||
|
|
|
|||
|
|
Dans ce TP, vous allez créer un **simulateur de combat Pokémon** en utilisant la Programmation Orientée Objet. Vous modéliserez des Pokémon, des dresseurs et des combats.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Partie 1 : La classe Pokémon
|
|||
|
|
|
|||
|
|
### Exercice 1 : Créer la classe de base
|
|||
|
|
|
|||
|
|
Créez une classe `Pokemon` avec les caractéristiques suivantes :
|
|||
|
|
|
|||
|
|
**Attributs :**
|
|||
|
|
- `nom` : nom du Pokémon (str)
|
|||
|
|
- `type_pokemon` : type élémentaire (str) — "Feu", "Eau", "Plante", "Electrik", etc.
|
|||
|
|
- `niveau` : niveau du Pokémon (int, par défaut 1)
|
|||
|
|
- `pv_max` : points de vie maximum (int, par défaut 100)
|
|||
|
|
- `pv` : points de vie actuels (int, initialisé à `pv_max`)
|
|||
|
|
- `attaque` : puissance d'attaque (int, par défaut 10)
|
|||
|
|
|
|||
|
|
**Méthodes :**
|
|||
|
|
- `__init__` : constructeur
|
|||
|
|
- `__repr__` : affiche le Pokémon sous la forme `"Pikachu (Electrik) - Nv.25 - 80/100 PV"`
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
class Pokemon:
|
|||
|
|
def __init__(self, nom, type_pokemon, niveau=1, pv_max=100, attaque=10):
|
|||
|
|
"""
|
|||
|
|
Constructeur de la classe Pokemon.
|
|||
|
|
|
|||
|
|
:param nom: (str) Nom du Pokémon
|
|||
|
|
:param type_pokemon: (str) Type élémentaire
|
|||
|
|
:param niveau: (int) Niveau du Pokémon
|
|||
|
|
:param pv_max: (int) Points de vie maximum
|
|||
|
|
:param attaque: (int) Puissance d'attaque
|
|||
|
|
"""
|
|||
|
|
# À compléter
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
def __repr__(self):
|
|||
|
|
"""Représentation textuelle du Pokémon."""
|
|||
|
|
# À compléter
|
|||
|
|
pass
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Tests :**
|
|||
|
|
```python
|
|||
|
|
>>> pikachu = Pokemon("Pikachu", "Electrik", niveau=25, pv_max=80, attaque=15)
|
|||
|
|
>>> print(pikachu)
|
|||
|
|
Pikachu (Electrik) - Nv.25 - 80/80 PV
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### Exercice 2 : Méthodes de combat
|
|||
|
|
|
|||
|
|
Ajoutez les méthodes suivantes à la classe `Pokemon` :
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
def est_ko(self):
|
|||
|
|
"""
|
|||
|
|
Vérifie si le Pokémon est KO.
|
|||
|
|
|
|||
|
|
:return: (bool) True si PV <= 0, False sinon
|
|||
|
|
"""
|
|||
|
|
# À compléter
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
def subir_degats(self, degats):
|
|||
|
|
"""
|
|||
|
|
Inflige des dégâts au Pokémon.
|
|||
|
|
Les PV ne peuvent pas descendre en dessous de 0.
|
|||
|
|
|
|||
|
|
:param degats: (int) Nombre de dégâts subis
|
|||
|
|
"""
|
|||
|
|
# À compléter
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
def attaquer(self, cible):
|
|||
|
|
"""
|
|||
|
|
Attaque un autre Pokémon.
|
|||
|
|
Affiche un message et inflige des dégâts à la cible.
|
|||
|
|
|
|||
|
|
:param cible: (Pokemon) Pokémon ciblé par l'attaque
|
|||
|
|
"""
|
|||
|
|
# À compléter
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
def soigner(self, soin):
|
|||
|
|
"""
|
|||
|
|
Soigne le Pokémon.
|
|||
|
|
Les PV ne peuvent pas dépasser pv_max.
|
|||
|
|
|
|||
|
|
:param soin: (int) Nombre de PV récupérés
|
|||
|
|
"""
|
|||
|
|
# À compléter
|
|||
|
|
pass
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Tests :**
|
|||
|
|
```python
|
|||
|
|
>>> pikachu = Pokemon("Pikachu", "Electrik", niveau=25, pv_max=80, attaque=15)
|
|||
|
|
>>> salameche = Pokemon("Salamèche", "Feu", niveau=20, pv_max=70, attaque=12)
|
|||
|
|
>>> pikachu.attaquer(salameche)
|
|||
|
|
Pikachu attaque Salamèche et inflige 15 dégâts !
|
|||
|
|
>>> print(salameche)
|
|||
|
|
Salamèche (Feu) - Nv.20 - 55/70 PV
|
|||
|
|
>>> salameche.est_ko()
|
|||
|
|
False
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### Exercice 3 : Système de faiblesses (Bonus)
|
|||
|
|
|
|||
|
|
En Pokémon, certains types sont plus efficaces contre d'autres :
|
|||
|
|
- **Eau** bat **Feu** (×2 dégâts)
|
|||
|
|
- **Feu** bat **Plante** (×2 dégâts)
|
|||
|
|
- **Plante** bat **Eau** (×2 dégâts)
|
|||
|
|
- **Electrik** bat **Eau** (×2 dégâts)
|
|||
|
|
|
|||
|
|
Modifiez la méthode `attaquer` pour prendre en compte les faiblesses :
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# Dictionnaire des faiblesses : type_attaquant -> liste des types faibles
|
|||
|
|
FAIBLESSES = {
|
|||
|
|
"Eau": ["Feu"],
|
|||
|
|
"Feu": ["Plante"],
|
|||
|
|
"Plante": ["Eau"],
|
|||
|
|
"Electrik": ["Eau"]
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
def attaquer(self, cible):
|
|||
|
|
"""
|
|||
|
|
Attaque un autre Pokémon avec prise en compte des faiblesses.
|
|||
|
|
"""
|
|||
|
|
degats = self.attaque
|
|||
|
|
|
|||
|
|
# Vérifier si le type de la cible est faible contre notre type
|
|||
|
|
if self.type_pokemon in FAIBLESSES:
|
|||
|
|
if cible.type_pokemon in FAIBLESSES[self.type_pokemon]:
|
|||
|
|
degats *= 2
|
|||
|
|
print(f"C'est super efficace !")
|
|||
|
|
|
|||
|
|
print(f"{self.nom} attaque {cible.nom} et inflige {degats} dégâts !")
|
|||
|
|
cible.subir_degats(degats)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Partie 2 : La classe Dresseur
|
|||
|
|
|
|||
|
|
### Exercice 4 : Créer la classe Dresseur
|
|||
|
|
|
|||
|
|
Un dresseur possède une équipe de Pokémon (maximum 6).
|
|||
|
|
|
|||
|
|
**Attributs :**
|
|||
|
|
- `nom` : nom du dresseur (str)
|
|||
|
|
- `equipe` : liste de Pokémon (list, vide par défaut)
|
|||
|
|
|
|||
|
|
**Méthodes :**
|
|||
|
|
- `__init__` : constructeur
|
|||
|
|
- `ajouter_pokemon(pokemon)` : ajoute un Pokémon à l'équipe (max 6)
|
|||
|
|
- `pokemon_disponibles()` : renvoie la liste des Pokémon non KO
|
|||
|
|
- `premier_pokemon_dispo()` : renvoie le premier Pokémon non KO ou None
|
|||
|
|
- `tous_ko()` : renvoie True si tous les Pokémon sont KO
|
|||
|
|
- `__repr__` : affiche le dresseur et son équipe
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
class Dresseur:
|
|||
|
|
def __init__(self, nom):
|
|||
|
|
"""
|
|||
|
|
Constructeur de la classe Dresseur.
|
|||
|
|
|
|||
|
|
:param nom: (str) Nom du dresseur
|
|||
|
|
"""
|
|||
|
|
# À compléter
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
def ajouter_pokemon(self, pokemon):
|
|||
|
|
"""
|
|||
|
|
Ajoute un Pokémon à l'équipe si possible (max 6).
|
|||
|
|
|
|||
|
|
:param pokemon: (Pokemon) Pokémon à ajouter
|
|||
|
|
:return: (bool) True si ajouté, False sinon
|
|||
|
|
"""
|
|||
|
|
# À compléter
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
def pokemon_disponibles(self):
|
|||
|
|
"""
|
|||
|
|
Renvoie la liste des Pokémon non KO.
|
|||
|
|
|
|||
|
|
:return: (list) Liste des Pokémon encore en état de combattre
|
|||
|
|
"""
|
|||
|
|
# À compléter
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
def premier_pokemon_dispo(self):
|
|||
|
|
"""
|
|||
|
|
Renvoie le premier Pokémon non KO.
|
|||
|
|
|
|||
|
|
:return: (Pokemon/None) Premier Pokémon dispo ou None
|
|||
|
|
"""
|
|||
|
|
# À compléter
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
def tous_ko(self):
|
|||
|
|
"""
|
|||
|
|
Vérifie si tous les Pokémon sont KO.
|
|||
|
|
|
|||
|
|
:return: (bool) True si tous KO, False sinon
|
|||
|
|
"""
|
|||
|
|
# À compléter
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
def __repr__(self):
|
|||
|
|
"""Représentation du dresseur."""
|
|||
|
|
# À compléter
|
|||
|
|
pass
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Tests :**
|
|||
|
|
```python
|
|||
|
|
>>> sacha = Dresseur("Sacha")
|
|||
|
|
>>> sacha.ajouter_pokemon(Pokemon("Pikachu", "Electrik", 25, 80, 15))
|
|||
|
|
True
|
|||
|
|
>>> sacha.ajouter_pokemon(Pokemon("Dracaufeu", "Feu", 50, 150, 25))
|
|||
|
|
True
|
|||
|
|
>>> print(sacha)
|
|||
|
|
Dresseur Sacha - 2 Pokémon
|
|||
|
|
- Pikachu (Electrik) - Nv.25 - 80/80 PV
|
|||
|
|
- Dracaufeu (Feu) - Nv.50 - 150/150 PV
|
|||
|
|
>>> sacha.tous_ko()
|
|||
|
|
False
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Partie 3 : La classe Combat
|
|||
|
|
|
|||
|
|
### Exercice 5 : Simulateur de combat
|
|||
|
|
|
|||
|
|
Créez une classe `Combat` qui simule un affrontement entre deux dresseurs.
|
|||
|
|
|
|||
|
|
**Attributs :**
|
|||
|
|
- `dresseur1` : premier dresseur (Dresseur)
|
|||
|
|
- `dresseur2` : second dresseur (Dresseur)
|
|||
|
|
- `tour` : numéro du tour actuel (int)
|
|||
|
|
|
|||
|
|
**Méthodes :**
|
|||
|
|
- `__init__` : constructeur
|
|||
|
|
- `lancer_combat()` : lance le combat jusqu'à ce qu'un dresseur n'ait plus de Pokémon
|
|||
|
|
- `afficher_etat()` : affiche l'état actuel du combat
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
class Combat:
|
|||
|
|
def __init__(self, dresseur1, dresseur2):
|
|||
|
|
"""
|
|||
|
|
Constructeur de la classe Combat.
|
|||
|
|
|
|||
|
|
:param dresseur1: (Dresseur) Premier dresseur
|
|||
|
|
:param dresseur2: (Dresseur) Second dresseur
|
|||
|
|
"""
|
|||
|
|
# À compléter
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
def afficher_etat(self):
|
|||
|
|
"""Affiche l'état actuel du combat."""
|
|||
|
|
print(f"\n{'='*40}")
|
|||
|
|
print(f"Tour {self.tour}")
|
|||
|
|
print(f"{'='*40}")
|
|||
|
|
# Afficher les Pokémon actifs
|
|||
|
|
# À compléter
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
def lancer_combat(self):
|
|||
|
|
"""
|
|||
|
|
Lance le combat tour par tour.
|
|||
|
|
Chaque tour, les deux Pokémon actifs s'attaquent.
|
|||
|
|
Quand un Pokémon est KO, le suivant prend sa place.
|
|||
|
|
Le combat s'arrête quand un dresseur n'a plus de Pokémon.
|
|||
|
|
"""
|
|||
|
|
print(f"\n*** COMBAT : {self.dresseur1.nom} VS {self.dresseur2.nom} ***\n")
|
|||
|
|
|
|||
|
|
while not self.dresseur1.tous_ko() and not self.dresseur2.tous_ko():
|
|||
|
|
self.tour += 1
|
|||
|
|
self.afficher_etat()
|
|||
|
|
|
|||
|
|
# Récupérer les Pokémon actifs
|
|||
|
|
poke1 = self.dresseur1.premier_pokemon_dispo()
|
|||
|
|
poke2 = self.dresseur2.premier_pokemon_dispo()
|
|||
|
|
|
|||
|
|
# Le Pokémon 1 attaque
|
|||
|
|
# À compléter
|
|||
|
|
|
|||
|
|
# Vérifier si Pokémon 2 est KO
|
|||
|
|
# À compléter
|
|||
|
|
|
|||
|
|
# Le Pokémon 2 attaque (s'il n'est pas KO)
|
|||
|
|
# À compléter
|
|||
|
|
|
|||
|
|
# Vérifier si Pokémon 1 est KO
|
|||
|
|
# À compléter
|
|||
|
|
|
|||
|
|
# Afficher le vainqueur
|
|||
|
|
# À compléter
|
|||
|
|
pass
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Exemple d'exécution :**
|
|||
|
|
```
|
|||
|
|
*** COMBAT : Sacha VS Pierre ***
|
|||
|
|
|
|||
|
|
========================================
|
|||
|
|
Tour 1
|
|||
|
|
========================================
|
|||
|
|
Sacha: Pikachu (80/80 PV)
|
|||
|
|
Pierre: Onix (120/120 PV)
|
|||
|
|
|
|||
|
|
Pikachu attaque Onix et inflige 15 dégâts !
|
|||
|
|
Onix attaque Pikachu et inflige 20 dégâts !
|
|||
|
|
|
|||
|
|
========================================
|
|||
|
|
Tour 2
|
|||
|
|
========================================
|
|||
|
|
Sacha: Pikachu (60/80 PV)
|
|||
|
|
Pierre: Onix (105/120 PV)
|
|||
|
|
|
|||
|
|
...
|
|||
|
|
|
|||
|
|
Pikachu est KO !
|
|||
|
|
Sacha envoie Dracaufeu !
|
|||
|
|
|
|||
|
|
...
|
|||
|
|
|
|||
|
|
Tous les Pokémon de Pierre sont KO !
|
|||
|
|
*** SACHA REMPORTE LE COMBAT ! ***
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Partie 4 : Améliorations
|
|||
|
|
|
|||
|
|
### Exercice 6 : Centre Pokémon
|
|||
|
|
|
|||
|
|
Créez une classe `CentrePokemon` qui permet de soigner une équipe :
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
class CentrePokemon:
|
|||
|
|
def __init__(self, ville):
|
|||
|
|
"""
|
|||
|
|
:param ville: (str) Ville où se trouve le centre
|
|||
|
|
"""
|
|||
|
|
self.ville = ville
|
|||
|
|
|
|||
|
|
def soigner_equipe(self, dresseur):
|
|||
|
|
"""
|
|||
|
|
Soigne tous les Pokémon d'un dresseur à 100% de leurs PV.
|
|||
|
|
|
|||
|
|
:param dresseur: (Dresseur) Dresseur dont l'équipe doit être soignée
|
|||
|
|
"""
|
|||
|
|
# À compléter
|
|||
|
|
pass
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### Exercice 7 : Capacités spéciales (Pour aller plus loin)
|
|||
|
|
|
|||
|
|
Créez une classe `Capacite` pour donner des attaques spéciales aux Pokémon :
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
class Capacite:
|
|||
|
|
def __init__(self, nom, puissance, type_capacite, pp_max):
|
|||
|
|
"""
|
|||
|
|
:param nom: (str) Nom de la capacité
|
|||
|
|
:param puissance: (int) Puissance de base
|
|||
|
|
:param type_capacite: (str) Type de la capacité
|
|||
|
|
:param pp_max: (int) Nombre d'utilisations max
|
|||
|
|
"""
|
|||
|
|
self.nom = nom
|
|||
|
|
self.puissance = puissance
|
|||
|
|
self.type_capacite = type_capacite
|
|||
|
|
self.pp_max = pp_max
|
|||
|
|
self.pp = pp_max
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Modifiez la classe `Pokemon` pour qu'un Pokémon possède une liste de capacités (max 4) et puisse choisir son attaque.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Résumé des classes
|
|||
|
|
|
|||
|
|
| Classe | Attributs | Méthodes principales |
|
|||
|
|
|--------|-----------|----------------------|
|
|||
|
|
| `Pokemon` | nom, type, niveau, pv, attaque | attaquer(), subir_degats(), est_ko() |
|
|||
|
|
| `Dresseur` | nom, equipe | ajouter_pokemon(), tous_ko() |
|
|||
|
|
| `Combat` | dresseur1, dresseur2, tour | lancer_combat() |
|
|||
|
|
| `CentrePokemon` | ville | soigner_equipe() |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Code de test final
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# Création des Pokémon
|
|||
|
|
pikachu = Pokemon("Pikachu", "Electrik", 25, 80, 15)
|
|||
|
|
dracaufeu = Pokemon("Dracaufeu", "Feu", 50, 150, 25)
|
|||
|
|
tortank = Pokemon("Tortank", "Eau", 45, 140, 22)
|
|||
|
|
onix = Pokemon("Onix", "Roche", 30, 120, 18)
|
|||
|
|
racaillou = Pokemon("Racaillou", "Roche", 20, 80, 12)
|
|||
|
|
|
|||
|
|
# Création des dresseurs
|
|||
|
|
sacha = Dresseur("Sacha")
|
|||
|
|
sacha.ajouter_pokemon(pikachu)
|
|||
|
|
sacha.ajouter_pokemon(dracaufeu)
|
|||
|
|
sacha.ajouter_pokemon(tortank)
|
|||
|
|
|
|||
|
|
pierre = Dresseur("Pierre")
|
|||
|
|
pierre.ajouter_pokemon(onix)
|
|||
|
|
pierre.ajouter_pokemon(racaillou)
|
|||
|
|
|
|||
|
|
# Lancement du combat
|
|||
|
|
combat = Combat(sacha, pierre)
|
|||
|
|
combat.lancer_combat()
|
|||
|
|
|
|||
|
|
# Soins au Centre Pokémon
|
|||
|
|
centre = CentrePokemon("Argenta")
|
|||
|
|
centre.soigner_equipe(sacha)
|
|||
|
|
print(sacha)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
Auteurs : Florian Mathieu, Enzo Frémeaux, Thimothée Decooster
|
|||
|
|
|
|||
|
|
Licence CC BY NC
|
|||
|
|
|
|||
|
|
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a> <br />Ce cours est mis à disposition selon les termes de la <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International</a>.
|