Exemple pas à pas
Bilbo et Gollum⚓︎
Création de la classe
Nous allons commencer par écrire une classe Personnage (qui sera dans un premier temps une coquille vide) et, à partir de cette classe, créer 2 instances : bilbo et gollum.
Tester :
Pour l'instant, notre classe ne sert à rien et nos instances d'objet ne peuvent rien faire. Comme il n'est pas possible de créer une classe totalement vide, nous avons utilisé l'instruction pass qui ne fait rien. Ensuite nous avons créé 2 instances de la classe Personnage : bilbo et gollum.
Le constructeur : la méthode __init__
Les attributs de l'objet doivent être définis dans la classe, à l'aide d'une méthode d'initialisation des attributs.
Une méthode particulière, nommée le constructeur, permet de définir les attributs dès l'instanciation d'un objet.
Cette méthode est définie dans le code source par la ligne : def __init__ (self):
Rappel : La méthode __init__
La méthode __init__ est automatiquement exécutée au moment de la création d'une instance.
Le mot self est obligatoirement le premier argument d'une méthode.
Le mot self représente l'instance. Quand vous définissez une instance de classe (bilbo ou gollum) le nom de votre instance va remplacer le mot self.
Dans le code source, nous allons avoir :
Ensuite lors de la création de l'instancegollum, Python va créer l'attribut vie de la variable gollum.Cet attribut aura pour valeur de départ la valeur donnée à
self.vie dans la méthode __init__
Il se passera exactement la même chose au moment de la création de l'instance bilbo, on aura automatiquement la création de l'attribut vie de la variable bilbo.
Exécutez ce code, puis dans la console, faites afficher les valeurs des attributs vie de gollum et de bilbo
# Tests (insensible à la casse)(Ctrl+I)
(Alt+: ; Ctrl pour inverser les colonnes)
(Esc)
Passer un argument
Imaginons que nos deux personnages n'aient pas au départ les mêmes points de vie ! Pour l'instant, impossible d'introduire cette contrainte (self.vie = 20)
Une méthode, comme une fonction, peut prendre des paramètres.
Le passage de paramètres se fait au moment de la création de l'instance. Modifiez le code pour que le nombre de vies soit un paramètre dont la valeur sera fixée lors de l'instanciation.
Votre code doit :
- Permettre de passer un argument
nb_vies. - Créer une instance de
Personnagenomméebilboinitialisée avec 20 vies. - Créer une autre instance,
gollum, avec 15 vies. - Afficher les valeurs de l'attribut
viepourbilbo - Afficher les valeurs de l'attribut
viepourgollum
# Tests (insensible à la casse)(Ctrl+I)
(Alt+: ; Ctrl pour inverser les colonnes)
(Esc)
Solution
Passer deux arguments
Compléter le code pour :
- Permettre de passer deux paramètres au constructeur.
- Utiliser les paramètres
nb_viesetagepour initialiser les attibutsvieetage. - Créer une instance,
gollum, avec 20 vies et 127 ans. - Afficher ceci (en utilisant les attributs) :
gollum a 127 ans et 20 vies
# Tests (insensible à la casse)(Ctrl+I)
(Alt+: ; Ctrl pour inverser les colonnes)
(Esc)
Solution
Ajouter des méthodes
Votre code doit :
- Ajouter une méthode
perd_une_viequi modifie l'attibutvie(retire une vie) - Ajouter une méthode
donne_etatqui renvoie la valeur de l'attibutvie - Créer un seul personnage,
gollum, avec 20 vies et 127 ans. - Créer une variable
etat_1égale à son nombre de vie, puis l'afficher - Modifier le nombre de vies avec la méthode
perd_une_vie - Créer une variable
etat_2égale à son nouveau nombre de vie, puis l'afficher.
# Tests (insensible à la casse)(Ctrl+I)
(Alt+: ; Ctrl pour inverser les colonnes)
(Esc)
Solution
class Personnage_4:
def __init__(self, nbre_vies, age):
self.vie = nbre_vies
self.age = age
def donne_etat(self):
return self.vie
def perd_une_vie(self):
self.vie = self.vie - 1
gollum = Personnage_4(20, 127)
etat_1 = gollum.donne_etat()
print(etat_1)
gollum.perd_une_vie()
etat_2 = gollum.donne_etat()
print(etat_2)
Mauvaise pratique
Vous avez sans doute remarqué que lors de "l'utilisation" des instances bilbo et gollum, nous avons uniquement utilisé des méthodes et nous n'avons plus directement utilisé des attributs (plus de gollum.vie). Il est important de savoir qu'en dehors de la classe l'utilisation des attributs est une mauvaise pratique en programmation orientée objet : les attributs doivent rester "à l'intérieur" de la classe, l'utilisateur de la classe ne doit pas les utiliser directement. Il peut les manipuler, mais uniquement par l'intermédiaire d'une méthode (la méthode perd_une_vie permet de manipuler l'attribut vie)
Boire une potion
Nos personnages peuvent boire une potion qui leur ajoute un point de vie.
Vous devez :
- Modifier la classe
Personnageen ajoutant une méthodeboire_potionqui ajoute un point de vie. - créer en dehors de la classe une fonction
simul(n, a)qui crée un personnage avecnvies, un âgea, lui fait boire une potion, et renvoie le nombre de vies.
Vous pourrez tester par exemple simul(10, 127) dans la console.
# Tests (insensible à la casse)(Ctrl+I)
(Alt+: ; Ctrl pour inverser les colonnes)
(Esc)
Solution
class Personnage_5:
def __init__(self, nbre_vies, age):
self.vie = nbre_vies
self.age = age
def donne_etat(self):
return self.vie
def perd_une_vie(self):
self.vie = self.vie - 1
def boire_potion(self):
self.vie = self.vie + 1
def simul(n, a):
mon_personnage = Personnage_5(n, a)
mon_personnage.boire_potion()
return mon_personnage.donne_etat()
Perdre plusieurs vies
Selon le type d'attaque subie, le personnage peut perdre plus ou moins de points de vie. Pour tenir compte de cet élément, remplacer la méthode perd_une_vie par la méthode perd_vies qui prend le nombre de vies perdues vies_perdues en paramètre.
Vous devez :
- écrire la méthode
perd_vies - instancier
gollumavec 15 vies et 100 ans - lui faire perdre 2 vies avec la méthode
perd_vies - Faire afficher le nombre de vies avec la méthode
donne_etat
Contrainte
vous ne pouvez pas utiliser la notation pointée gollum.vie
# Tests (insensible à la casse)(Ctrl+I)
(Alt+: ; Ctrl pour inverser les colonnes)
(Esc)
Solution
class Personnage_6:
def __init__(self, nbre_vies, age):
self.vie = nbre_vies
self.age = age
def donne_etat(self):
return self.vie
def perd_vies(self, vies_perdues):
self.vie = self.vie - vies_perdues
def boire_potion(self):
self.vie = self.vie + 1
gollum = Personnage_6(15, 100)
gollum.perd_vies(2)
print(gollum.donne_etat())
Un peu de hasard ne nuira pas...
Modifier le code précédent, de façon que perd_vies(self, vies_perdues) retire entre 1 et vies_perdues vies au personnage attaqué.
Vous devez :
- Modifier la méthode
perd_vies - Compléter le code de façon à créer un personnage ayant 100 vies, 130 ans, puis qui subit 3 attaques consécutives, lui infligeant chacune 1 à 10 vies perdues... Il faudra ensuite afficher son nombre de vies.
Vous pouvez aussi imaginer vos propres scénarios, en rajoutant le fait de boire de la potion ...
# Tests (insensible à la casse)(Ctrl+I)
(Alt+: ; Ctrl pour inverser les colonnes)
(Esc)
Solution
from random import randint
class Personnage_7:
def __init__(self, nbre_vies, age):
self.vie = nbre_vies
self.age = age
def donne_etat(self):
return self.vie
def perd_vies(self, vies_perdues):
perdues = randint(1, vies_perdues)
self.vie = self.vie - perdues
def boire_potion(self):
self.vie = self.vie + 1
monstre = Personnage_7(100, 130)
for i in range(3):
monstre.perd_vies(10)
print(monstre.donne_etat())
Plus mort que mort ?
La méthode perd_vies doit être écrite de façon à ne jamais renvoyer un nombre de vies négatif. Si le nombre de vies est négatif, il doit être mis à 0.
Vous devez :
- Modifier la méthode
perd_vies - Completer le code de façon à créer un personnage ayant 100 vies puis qui subit des attaques consécutives, lui infligeant chacune 1 à 10 vies perdues, jusqu'à ce qu'il n'ait plus aucune vie. Le code affichera le nombre d'attaques subies.
# Tests (insensible à la casse)(Ctrl+I)
(Alt+: ; Ctrl pour inverser les colonnes)
(Esc)
Solution
from random import randint
class Personnage_8:
def __init__(self, nbre_vies, age):
self.vie = nbre_vies
self.age = age
def donne_etat(self):
return self.vie
def perd_vies(self, vies_perdues):
perdues = randint(1, vies_perdues)
self.vie = self.vie - perdues
if self.vie < 0:
self.vie = 0
def boire_potion(self):
self.vie = self.vie + 1
monstre = Personnage_8(100, 130)
cpt = 0
while monstre.donne_etat() > 0:
monstre.perd_vies(10)
cpt = cpt + 1
print(monstre.donne_etat())
print("Il y a eu ", cpt, " attaques")
Un combat
Organisez un combat virtuel entre nos 2 personnages Bilbo et Gollum:
-
Le code décide aléatoirement quel personnage va attaquer en premier
-
Tant que Bilbo et Gollum sont en vie:
- Un personnage attaque (la victime perd de 1 à 10 vies)
- On change de personnage
Tant qu'aucun des deux n'est mort, le combat continue
- Quand un des deux est mort, on affiche le nombre d'attaques qui ont été menées durant le combat, et l'état de chaque personnage.
Aide pour alterner les combattants
On peut utiliser une variable attaquant = randint(0, 1)
Pour changer d'attaquant, on peut écrire attaquant = 1 - attaquant
# Tests (insensible à la casse)(Ctrl+I)
(Alt+: ; Ctrl pour inverser les colonnes)
(Esc)
Solution
from random import randint
class Personnage_9:
def __init__(self, nbre_vies, age):
self.vie = nbre_vies
self.age = age
def donne_etat(self):
return self.vie
def perd_vies(self, vies_perdues):
perdues = randint(1, vies_perdues)
self.vie = self.vie - perdues
if self.vie < 0:
self.vie = 0
def boire_potion(self):
self.vie = self.vie + 1
gollum = Personnage_9(100, 127)
bilbo = Personnage_9(100, 127)
nb_attaques = 0
attaquant = randint(0, 1)
while gollum.donne_etat() > 0 and bilbo.donne_etat() > 0 :
if attaquant == 0 :
gollum.perd_vies(10)
else :
bilbo.perd_vies(10)
nb_attaques = nb_attaques + 1
attaquant = 1 - attaquant
print(nb_attaques)
print("Gollum a ", gollum.donne_etat(), "vies")
print("bilbo a ", bilbo.donne_etat(), "vies")
Facultatif : Faites vos propres règles et implémentez les
Il n'y aura pas de correction toute faite à cette question ... 😊
Modifiez (à votre convenance) les règles et améliorez le programme en modifiant des méthodes ou en implémentant vos propres méthodes.
Quelques propositions si vous ne voyez pas trop quoi ajouter :
-
Dans l’initialisation, on ne peut donner de nom au personnage !
-
créez un attribut
nomqu’on doit donner en premier paramètre : on crée une instance dePersonnagecomme ceci :gollum = Personnage("Gollum", 100, 127) -
créez une méthode
donne_nomqui renvoie le nom du personnage.
-
-
Modifiez la fonction
gamepour qu’elle tienne compte du nom du personnage.
On doit pouvoir créer d’autres personnages et les messages doivent tenir compte des noms de ceux-ci.>>> frodon = Personnage("Frodon", 100, 70) >>> araignee = Personnage("Araignée", 50, 4) >>> game() Frodon est vainqueur, il lui reste encore 3 points alors que Araignée est mortRemarquez bien que la signature de la fonction
gameest différente !On doit créer les personnages AVANT de l’appeler. Il faut changer plusieurs éléments.
-
Améliorez encore la fonction
gamepour qu’elle affiche un journal détaillé du combat :>>> aragorn =Personnage("Aragorn", 100, 35) >>> orc = Personnage("Orc", 100, 25) >>> game(aragorn, orc) Aragorn perd un point de vie Orc perd deux points de vie ... Aragorn perd deux points de vie Orc perd deux points de vie Orc est vainqueur, il lui reste encore 3 points alors que Aragorn est mort -
Revenons à
Personnage
On dispose maintenant des méthodes suivantes :class Personnage: | | donne_etat | --> int | renvoie le nombre de pts de vie | | perd_vies | enleve un ou deux points de vie | | donne_nom | --> str | renvoie le nom du personnageOn veut créer un attribut
chancelors de l’instanciation du personnage. C’est un entier entre 0 et 4.L’effet de la chance est le suivant :
-
dans la méthode
perd_vie, on tire toujours un nombre aléatoire entre 0 et 1.-
Si ce nombre multiplié par 10 dépasse la chance du personnage, il perd un point de vie.
-
Sinon il ne perd pas de vie et on affiche “Aragorn a de la chance !”
Par exemple, Aragorn a 2 de chance.
-
dans
perd_vies, on tire 0.3,
10 * 0.3 = 3et3 > 2: il perd un point de vie. -
dans
perd_vies, on tire 0.12345
10 * 0.12345 = 1.2345et1.2345 < 2: il ne perd pas de vie.
-
-
Il faut aussi changer la méthode
initpour pouvoir créer nos personnages ainsi :aragorn = Personnage("Aragorn", 100, 35, 2)
Implémentez la chance et faites quelques essais.
Attention, si vous donnez une chance trop élevée, le personnage ne perdra jamais de vie et la boucle de la fonction
gamesera infinie ! -
-
Maintenant qu’on peut donner un attribut chance, il faut protéger le programme.
Une valeur de chance trop élevée peut conduire à un programme qui ne termine jamais, il suffit de donner une chance de 10 pour qu’un personnage soit invicible !
Nous allons créer une méthode interne
__limiter_chancequi empêche la chance d’être supérieure à 4.Si le paramètre
chanceest inférieure ou égale à 4, il est inchangé, S’il dépasse 4, il est ramené à 4.Cette méthode interne ne sera pas appelée par les éléments extérieurs au programme, seulement par le programme lui même !
On utilise cette méthode interne dans
__init__, il faut penser à l’appeler.
Voici aussi d'autre possibilités :
- Quand une personne attaque, elle peut en réalité décider de ne pas le faire et à la place, boire une potion qui lui rend par exemple 1-8 vies. Le code devra activer cette action si perso.vie est trop bas (à vous de préciser!)
- Un personnage peut se mettre en fuite, dans ce cas par exemple, il passe son tour, l'autre peut porter une dernière attaque, mais le combat s'arrête ensuite
- Les possibilités sont infinies, ajouter une attaque spéciale, ajouter une vie à chaque tour (autoguérison) etc.
Et c’est la fin de cette très longue partie !
# Tests (insensible à la casse)(Ctrl+I)
(Alt+: ; Ctrl pour inverser les colonnes)
(Esc)
# Tests(insensible à la casse)(Ctrl+I)
(Alt+: ; Ctrl pour inverser les colonnes)
(Esc)