Physique-Chimie & NSI

Cours complets et originaux de Physique-Chimie & NSI

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 :

  1. le nom d’une classe ;
  2. un nom d’attribut d’instance ;
  3. un nom de méthode ;
  4. 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 :

  1. guerrier.points_de_vie
  2. magicien.points_de_vie
  3. guerrier.arme
  4. magicien.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.arme n’est pas None), la cible subit une perte de points de vie égale aux dégâts de cette arme (en appelant la méthode perdre_vie de la cible).
  • Si le personnage attaquant n’a pas d’arme (l’attribut self.arme vaut None), la cible perd 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 :

  1. Nom de classe : Arme
  2. Attribut d’instance : nom ou degats
  3. Méthode : __init__ ou get_degats
  4. Variable référençant un objet : arc

0,5 pt par identification correcte.

[2]

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(...)).

[1]

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.

[1]

Partie B : Suivi d’état et exécution pas-à-pas (3,5 points)

4. Valeur des expressions :

  1. guerrier.points_de_vie : 55 (80 initial - 25)
  2. magicien.points_de_vie : 100 (valeur par défaut)
  3. guerrier.arme : None
  4. magicien.arme.nom : "Bâton magique"
[2]

5.

  • print(magicien.arme.get_degats()) affiche 15.
  • Pour guerrier.arme.get_degats() : l’attribut guerrier.arme vaut None. Tenter d’accéder à une méthode sur None lève une erreur de type AttributeError (ou fait planter le programme car None ne possède pas de méthode get_degats).
[1,5]

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
			
[1]

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)
			
[2]

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}"
			
[1]