Licence CC BY-SA

TP : Combat en tour par tour

Il est temps maintenant de mettre en pratique ce que l’on a vu jusqu’ici avec un premier TP.

Présentation générale du TP

Afin de nous accompagner dans l’apprentissage du Python, voici un projet que je vous propose de réaliser au long des chapitres. L’idée est d’améliorer ce projet au fur et à mesure avec les nouvelles compétences que vous aurez acquises.

L’objectif final du projet est de réaliser un système de combat au tour par tour entre deux monstres, à la manière de Pokémon. Les deux monstres seront alors dotés d’une barre de vie (PV) et d’attaques. Les attaques se caractérisent par le nombre de points de vie qu’elles infligent en dégâts.

À chaque tour de jeu, une attaque est sélectionnée pour chaque monstre et les dégâts correspondants sont infligés à l’adversaire. Un monstre est KO quand sa barre de vie est vide. Le survivant remporte le combat.

Dans ces TP tu seras accompagné par Pythachu, Pythard et Ponytha.

Attrapez-les tous !
Attrapez-les tous !

Pour plus de facilité, le jeu se déroulera en mode texte dans le terminal. Nous allons y aller par étapes et ce TP constitue la première étape : on va ici chercher à réaliser un seul tour de jeu.

Initialisation du jeu

Tout d’abord, avant de faire un premier tour de combat, il faut procéder à l’initialisation du jeu. En effet, il nous faut connaître les monstres en jeu et leur nombre initial de points de vie.

Pour cela on utilisera la fonction input afin de demander aux deux joueurs les différentes informations. Nous les conserverons dans des variables et les afficherons en début de partie à l’aide de la fonction print.

Entrez le nom du 1er joueur : pythachu
Et son nombre de PV : 50
Entrez le nom du 2ème joueur : pythard
Et son nombre de PV : 40

+++++++++++++++++++++++++++++++++++++++++++++
+ Pythachu (50 PV) affronte Pythard (40 PV) +
+++++++++++++++++++++++++++++++++++++++++++++

Vous le voyez, j’ai ajouté un cadre autour du message à afficher. On peut faire ça simplement à l’aide des opérateurs + et * que nous avons vus pour les chaînes de caractères.
La fonction len vous sera utile aussi pour que la largeur du cadre s’adapte à la taille du texte.

On peut voir que j’ai passé en majuscule la première lettre des noms, saurez-vous retrouver la méthode qui permet ça ? Aussi, il nous faudra penser à convertir les PV saisis pour les traiter en tant que nombres.

Solution

Cette première étape devrait se faire assez facilement, et je vous laisse revoir les chapitres précédents en cas de doutes.

Voici tout de même la solution que je propose à ce début d’exercice, à comparer avec la vôtre. Je la mets en balise secret, suivie de quelques explications.

name1 = input('Entrez le nom du 1er joueur : ').capitalize()
pv1 = int(input('Et son nombre de PV : '))

name2 = input('Entrez le nom du 2ème joueur : ').capitalize()
pv2 = int(input('Et son nombre de PV : '))

print()

message = name1 + ' (' + str(pv1) + ' PV) affronte ' + name2 + ' (' + str(pv2) + ' PV)'
print('+' * (len(message)+4))
print('+', message, '+')
print('+' * (len(message)+4))
  • La méthode capitalize, appliquée directement sur le retour d'input nous permet de transformer un 'pytachu' entré en 'Pythachu'.
  • Les points de vie sont convertis en nombres à l’aide d’appels à int.
  • print peut s’utiliser sans arguments pour juste afficher une ligne vide et séparer les informations les unes des autres.
  • Pour l’affichage du cadre, on commence par forger une variable message qui contient le message à afficher. Ça se fait aisément à l’aide de concaténations (+) entre nos différents bouts de texte.
  • À partir de la taille du message, on peut alors afficher les lignes haute et basse du cadre. Mais attention : avec les marges, elles comprennent 4 caractères de plus que le message.
  • Enfin, pour l’affichage du message à proprement parler, on peut juste utiliser les différents arguments de print, sans concaténation.

Nous pouvons maintenant passer à la suite du TP.

Tour de jeu

Un tour de jeu se divise en deux manches, d’abord le premier monstre attaque le second, puis l’inverse.

Nous ne sommes pour l’instant pas en mesure de traiter une liste d’attaques, nous demanderons alors simplement aux joueurs d’entrer le nombre de dégâts qu’ils souhaitent infliger à l’adversaire. Comme précédemment, on utilisera pour ça la fonction input et la conversion dans le type voulu.

À partir de ces dégâts, on calculera alors le nombre de points de vie restants du monstre cible, afin de les afficher dans un récapitulatif. Nous utiliserons toutes les données recueillies pour fournir le plus d’informations possibles aux joueurs.

À la suite de nos deux manches, on pourra afficher un résumé de la partie.

Voici ce à quoi pourrait ressembler un tour de jeu.

Pythachu, combien de dégâts infligez-vous à Pythard ? 30

+++++++++++++++++++++++++++++++++++++++++++
+ Pythachu attaque Pythard qui perd 30 PV +
+ Pythard a maintenant 10 PV              +
+++++++++++++++++++++++++++++++++++++++++++

Pythard, combien de dégâts infligez-vous à Pythachu ? 15

+++++++++++++++++++++++++++++++++++++++++++
+ Pythard attaque Pythachu qui perd 15 PV +
+ Pythachu a maintenant 35 PV             +
+++++++++++++++++++++++++++++++++++++++++++

+++++++++++++++++++++++
+ Résulat du combat : +
+ Pythachu a 35 PV    +
+ Pythard a 10 PV     +
+++++++++++++++++++++++
Solution

L’affichage correct du cadre autour des messages pourrait vous donner du fil à retordre, pensez à la fonction max pour en connaître la taille.

Je vous propose la solution suivante à cette deuxième partie, mais prenez d’abord le temps de compléter la vôtre.

att1 = int(input(name1 + ', combien de PV infligez-vous à ' + name2 + ' ? '))

print()

pv2 -= att1
msg1 = name1 + ' attaque ' + name2 + ' qui perd ' + str(att1) + ' PV'
msg2 = name2 + ' a maintenant ' + str(pv2) + ' PV'
max_size = max(len(msg1), len(msg2))
msg1 += ' ' * (max_size - len(msg1))
msg2 += ' ' * (max_size - len(msg2))
print('+' * (max_size+4))
print('+', msg1, '+')
print('+', msg2, '+')
print('+' * (max_size+4))

print()

att2 = int(input(name2 + ', combien de PV infligez-vous à ' + name1 + ' ? '))

print()

pv1 -= att2
msg1 = name2 + ' attaque ' + name1 + ' qui perd ' + str(att2) + ' PV'
msg2 = name1 + ' a maintenant ' + str(pv1) + ' PV'
max_size = max(len(msg1), len(msg2))
msg1 += ' ' * (max_size - len(msg1))
msg2 += ' ' * (max_size - len(msg2))
print('+' * (max_size+4))
print('+', msg1, '+')
print('+', msg2, '+')
print('+' * (max_size+4))

print()

msg1 = 'Résulat du combat :'
msg2 = name1 + ' a ' + str(pv1) + ' PV'
msg3 = name2 + ' a ' + str(pv2) + ' PV'
max_size = max(len(msg1), len(msg2), len(msg3))
msg1 += ' ' * (max_size - len(msg1))
msg2 += ' ' * (max_size - len(msg2))
msg3 += ' ' * (max_size - len(msg3))
print('+' * (max_size+4))
print('+', msg1, '+')
print('+', msg2, '+')
print('+', msg3, '+')
print('+' * (max_size+4))
  • On appelle input avec un message formaté à l’aide de concaténations, on prend soin d’en convertir le retour en int.
  • Ce nombre de dégâts est ensuite utilisé pour décrémenter les PV de l’ennemi.
  • Pour l’affichage du cadre, celui-ci contient maintenant deux lignes différentes. Il faut alors calculer la taille maximale (max_size) à l’aide de la fonction max pour connaître la taille des lignes haute et basse.
  • La longueur maximale sert aussi à calculer les marges pour que nos deux lignes s’intègrent correctement dans le cadre, en ajoutant autant d’espaces que besoin. On n’a pas peur pour cela de multiplier notre chaîne ' ' par un nombre négatif.
  • On remarque pas mal de répétitions dans le code, ce n’est pas idéal et on verra comment y remédier dans un prochain chapitre.

Voilà ce qui conclut notre premier TP, j’espère qu’il vous a plu, même s’il est très limité pour le moment. Vous pouvez continuer à travailler dessus pour vous exercer et l’améliorer au fil du temps.
Nous y reviendrons au cours des prochains chapitres pour lui ajouter de nouvelles fonctionnalités.

Il serait possible de réaliser plusieurs tours de jeu en dupliquant la partie de code dédiée autant de fois que l’on voudrait voir de tours, mais ce n’est pas une bonne pratique. Nous verrons par la suite comment faire cela proprement.