Devoir n°2
Programmation Orienté Objet
45 minutes
Ce devoir sur table évalue la maîtrise de la récursivité et de la programmation orientée objet. Il est composé de deux exercices indépendants. La clarté de la rédaction et la précision du vocabulaire sont prises en compte.
On modélise un jeu de rôle textuel dans lequel des personnages peuvent s’équiper d’armes et s’affronter. On commence par définir une première classe Arme :
class Arme:
def __init__(self, nom, degats):
self.nom = nom
self.degats = degats
def get_degats(self):
return self.degats
Partie A : Vocabulaire et rétro-ingénierie
On considère l’instruction suivante : arc = Arme("Arc court", 12)
1. À partir du code de la classe Arme et de l’instruction ci-dessus, identifier formellement :
- le nom d’une classe ;
- un nom d’attribut d’instance ;
- un nom de méthode ;
- une variable référençant un objet (une instance).
2. Quel est le rôle de la méthode __init__ ? À quel moment précis est-elle exécutée ?
3. Expliquer la signification et le rôle du premier paramètre self présent dans la définition des méthodes.
Partie B : Suivi d’état et exécution pas-à-pas
On définit maintenant la classe Personnage suivante :
class Personnage:
def __init__(self, nom, points_de_vie=100):
self.nom = nom
self.points_de_vie = points_de_vie
self.arme = None
def equiper(self, nouvelle_arme):
self.arme = nouvelle_arme
def perdre_vie(self, quantite):
self.points_de_vie = self.points_de_vie - quantite
if self.points_de_vie < 0:
self.points_de_vie = 0
On exécute la séquence d’instructions suivante :
guerrier = Personnage("Arthur", 80)
magicien = Personnage("Merlin")
baton = Arme("Bâton magique", 15)
magicien.equiper(baton)
guerrier.perdre_vie(25)
4. À la fin de cette exécution, donner la valeur des expressions suivantes :
guerrier.points_de_viemagicien.points_de_vieguerrier.armemagicien.arme.nom
5. Indiquer ce qui sera affiché lors de l’exécution de la commande suivante :
print(magicien.arme.get_degats())
Que se passerait-il si on tentait d’exécuter la commande print(guerrier.arme.get_degats()) ? Justifier la réponse.
Partie C : Conception et enrichissement de la classe
On souhaite ajouter de nouvelles fonctionnalités à la classe Personnage.
6. Écrire la méthode est_vivant(self) qui renvoie True si le personnage dispose d’au moins un point de vie (strictement supérieur à 0), et False sinon.
7. Écrire la méthode attaquer(self, cible) qui fait attaquer une autre instance cible de la classe Personnage passée en argument :
- Si le personnage attaquant possède une arme (l’attribut
self.armen’est pasNone), laciblesubit une perte de points de vie égale aux dégâts de cette arme (en appelant la méthodeperdre_viede la cible). - Si le personnage attaquant n’a pas d’arme (l’attribut
self.armevautNone), lacibleperd forfaitairement 5 points de vie.
8. Question bonus. Lorsqu’on affiche un objet à l’écran avec print(guerrier), on souhaite obtenir un résumé textuel clair du personnage. Écrire la méthode __str__(self) qui renvoie :
- la chaîne de caractères
"Arthur (55 PV) - Arme : Aucune"si le personnage ne possède pas d’arme ; - la chaîne de caractères
"Merlin (100 PV) - Arme : Bâton magique"si le personnage possède une arme.
Note : le nom, les PV et le nom de l’arme doivent correspondre aux attributs de l’instance courante.
Correction et barème
Partie A : Vocabulaire et rétro-ingénierie (3,5 points)
1. Identification dans le code :
- Nom de classe :
Arme - Attribut d’instance :
nomoudegats - Méthode :
__init__ouget_degats - Variable référençant un objet :
arc
0,5 pt par identification correcte.
2. Rôle de __init__ :
C’est le constructeur de la classe. Cette méthode initialise les attributs de la nouvelle instance lors de sa création. Elle est automatiquement appelée au moment de l’instanciation d’un objet (par exemple lors de l’instruction Arme(...)).
3. Rôle du paramètre self :
self fait référence à l’instance courante de l’objet sur laquelle la méthode est appelée. Il permet d’accéder aux attributs et méthodes propres à cette instance et de les modifier.
Partie B : Suivi d’état et exécution pas-à-pas (3,5 points)
4. Valeur des expressions :
guerrier.points_de_vie:55(80 initial - 25)magicien.points_de_vie:100(valeur par défaut)guerrier.arme:Nonemagicien.arme.nom:"Bâton magique"
5.
print(magicien.arme.get_degats())affiche15.- Pour
guerrier.arme.get_degats(): l’attributguerrier.armevautNone. Tenter d’accéder à une méthode surNonelève une erreur de typeAttributeError(ou fait planter le programme carNonene possède pas de méthodeget_degats).
Partie C : Conception et enrichissement de la classe (6 points)
6. Méthode est_vivant :
def est_vivant(self):
return self.points_de_vie > 0
7. Méthode attaquer :
def attaquer(self, cible):
if self.arme is not None:
degats = self.arme.degats # ou self.arme.get_degats()
cible.perdre_vie(degats)
else:
cible.perdre_vie(5)
8. Méthode __str__ :
def __str__(self):
if self.arme is None:
nom_arme = "Aucune"
else:
nom_arme = self.arme.nom
return f"{self.nom} ({self.points_de_vie} PV) - Arme : {nom_arme}"