☀️
420-1G2-HU Logique de programmation
  • 👋Bienvenue dans le cours de logique de programmation!
  • Bases de la logique de programmation
    • Concepts de la programmation
    • Les opérateurs
      • Exercices
    • Les commentaires
  • Les données
    • Les données et types simples
    • Les variables, les constantes et les opérations de base
    • Les opérations d'écriture et de lecture
    • Les opérations sur les chaînes de caractères
    • Laboratoire 1 - données
    • Laboratoire 2 - données
  • Les collections de données
    • Les listes
    • Les opérations sur les listes
    • Laboratoire listes - solution
    • Les dictionnaires
      • Exercices
  • Différents types de traitements
    • Structures logiques séquentielle
    • Structures logiques conditionnelles (if/else/elif)
    • Structures logiques répétitives (boucles)
      • Exercices de base
      • Laboratoire boucles - solution
  • Modularisation
    • Création et appels des fonctions
    • La documentation des fonctions
    • Annotation de types dans les fonctions
    • Laboratoire - fonctions (niveau débutant)
    • Révision express fonctions
    • Les modules
      • Laboratoire
  • La portée des variables
  • Débogage
    • 🫂Le débogueur, c'est ton ami!
      • Introductions aux outils de débogage
      • Techniques de débogage
    • Les erreurs et exceptions
      • Introduction aux notions d’erreurs
      • Les exceptions et leurs gestion
      • Exercices de base - avec solutions
      • Laboratoire débogage et gestion des erreurs -solution
  • Tests unitaires
    • Tests unitaires
    • Exercice
  • Cryptographie
    • Introduction à la cryptographie
  • Les fichiers
    • Accès aux fichiers
  • Résolution de problèmes
    • Résolution de problèmes : exercice introductif
    • Étapes d'analyse et de résolution de problèmes
  • Activités avec Légos
    • Introduction à la programmation
    • Consolidation sur les fonctions avec des blocs
    • Pratiquer les boucles avec des blocs
  • Laboratoires
    • Simulation combat - dragon vs chevalier
    • Simulateur de bataille - Les anneaux du pouvoir
    • Jeu de cartes
    • Lien logique mathématique
      • Algèbre de Boole
    • Crypto variée
    • Après Noël
  • git - système de gestion de versions
    • Introduction à Git
    • Étapes de création des dépôts Git
  • Classes inversées
    • Résolution de problèmes, fonctions et traitements conditionnels
  • Examens
    • Examen 2 - 2023
    • Examen 3 - 2023
    • Examen 2 - 2024
  • Révision
    • Fonctions, gestion d'erreurs et tests unitaires
    • Résolution de problème
  • Trucs utiles
    • Check-list
Powered by GitBook
On this page
  • But
  • Durée : 4 heures
  • Matériel
  • Énoncé
  • Réutilisabilité
  • Fonctionnalité : Plusieurs attaques successives
  • Fonctionnalité : attaques à tour de rôle
  • Débogage
  • Nouvelle fonctionnalité : Potion de soin
  • Fonctionnalité : générer aléatoirement la liste de dégâts
  1. Laboratoires

Simulation combat - dragon vs chevalier

PreviousPratiquer les boucles avec des blocsNextSimulateur de bataille - Les anneaux du pouvoir

Last updated 7 months ago

But

  • Modifier un code.

  • Travailler encore et encore sur les fonctions.

  • Utilisation de boucles whiles et for.

  • Utilisation de base des listes.

  • Déboguer et corriger les erreurs.

  • Faire de la gestion d'exceptions.

  • Introduction aux modules (random).

Durée : 4 heures

Matériel

Un projet vous a été fourni, il contient :

  • Un fichier nommé "simulation_combat.py" dans lequel il y a le code source que vous devez corriger et compléter.

  • [ Optionnel mais conseillé] Un fichier nommé "test_simulation_combat.py" content quelques tests automatiques pour vérifier vos solutions. Vous n'avez pas besoin de le modifier, il vous servira à des fins de vérification simplement pour l'instant. On vous montrera comment exécuter les tests unitaires.

    • Pour utiliser les tests unitaires, vous avez besoin d'installer le module pytest. Les étapes sont montrées , vous avez le choix entre la méthode en ligne de commande et la méthode dans l’IDE.

Téléchargez et décompressez ce fichier zip, puis copiez-le dans votre dépôt local git projets-python-1-g-3-[votre_nom].

Énoncé

On vous demande de programmer une simulation de combat entre un chevalier et un dragon. Chaque personnage a un certain nombre de points de vie (PV) et peut infliger des dégâts à son adversaire à chaque tour.

Un dégât représente le nombre de points que la victime (chevalier ou dragon) va perdre.

Voici le programme qui permet de faire différentes attaques :

# Points de vie initiaux
points_vie_chevalier = 100
points_vie_dragon = 120

# Le chevalier attaque le dragon
degats_chevalier = 20
points_vie_dragon = points_vie_dragon - degats_chevalier
print(f"Le chevalier attaque ! Le dragon perd {degats_chevalier} points de vie.")
print(f"Points de vie du dragon : {points_vie_dragon}")

# Le dragon attaque le chevalier
degats_dragon = 25
points_vie_chevalier = points_vie_chevalier - degats_dragon
print(f"Le dragon attaque ! Le chevalier perd {degats_dragon} points de vie.")
print(f"Points de vie du chevalier : {points_vie_chevalier}")

# Le chevalier attaque de nouveau le dragon
degats_chevalier = 15
points_vie_dragon = points_vie_dragon - degats_chevalier
print(f"Le chevalier attaque ! Le dragon perd {degats_chevalier} points de vie.")
print(f"Points de vie du dragon : {points_vie_dragon}")

# Le dragon attaque de nouveau le chevalier
degats_dragon = 30
points_vie_chevalier = points_vie_chevalier - degats_dragon
print(f"Le dragon attaque ! Le chevalier perd {degats_dragon} points de vie.")
print(f"Points de vie du chevalier : {points_vie_chevalier}")

Réutilisabilité

Comme vous avez dû le remarquer, un bloc de code se répète plusieurs fois. Que feriez-vous pour résoudre cette répétition qui rend votre programme disgracieux ?

Réponse

Les fonctions nous permette la réutilisabilité du code.

Vous devez simplifier ce programme en créant une fonction en suivant le processus suivant :

  1. Définissez la signature de la fonction (nom de la fonction et ses ).

  2. Complétez le corp de la fonction.

  3. Ajoutez le docstring.

  4. Exécutez le test unitaire de la fonction avant de la vérifier.

Solution

[Dans ce qui suit, je vous donne une solution générale au problème. Il est possible que le programme proposé ne soit pas complet, qu'il ne traite pas tous les cas limites, etc. Vous devez vous assurer du bon fonctionnement de votre programme selon tous les critères vus depuis le début de la session (traitement des exceptions, cas limites, validation de données, etc.).]

  • Nom de la fonction "attaquer", voir le docstring pour la description.

  • Les paramètres d'entrée de la fonction :

    • nom_attaquant et nom_victime (l'attaquant et la victime peuvent être le dragon ou le chevalier, chacun leurs tous)

    • degats.

    • points_vie_victime.

def attaquer(nom_attaquant, nom_victime, degats, points_vie_victime):
    """
    Cette fonction effectue une attaque d'un personnage contre un autre,
    réduit les points de vie de la victime, et affiche le résultat de
    l'attaque.

    :param nom_attaquant: Le nom de l'attaquant.
    :param nom_victime: Le nom de la victime.
    :param degats: Les points de dégâts infligés à la victime.
    :param points_vie_victime: Les points de vie actuels de la victime avant l'attaque.
    :return: Les points de vie de la victime après l'attaque.
    """
    
    points_vie_victime = points_vie_victime - degats
    print(f"{nom_attaquant} attaque ! {nom_victime} perd {degats} points de vie.")
    print(f"Points de vie du {nom_victime} : {points_vie_victime}")
    return points_vie_victime

if __name__ == "__main__":
    # Points de vie initiaux
    points_vie_chevalier = 100
    points_vie_dragon = 120

    points_vie_dragon = attaquer("chevalier", "dragon", 20, points_vie_dragon)
    points_vie_chevalier = attaquer("dragon", "chevalier", 25, points_vie_chevalier)
    points_vie_dragon = attaquer("chevalier", "dragon", 15, points_vie_dragon)
    points_vie_chevalier = attaquer("dragon", "chevalier", 30, points_vie_chevalier)

Fonctionnalité : Plusieurs attaques successives

Nous pourrions aussi imaginer un scénario où un attaquant réalise plusieurs attaques successives contre une victime. Lorsque les points de vie son épuisés, la victime est vaincue.

Quelle est la structure de données que vous utiliserez pour avoir plusieurs attaques successives?

Réponse

Une liste de dégâts.

  • Modifiez la signature de votre fonction de façon à prendre en paramètre une liste de dégâts à la place d'un seul dégât.

    • Vous pouvez aussi la copier, lui changer de nom et faire le reste des ajustements.

  • Faites les ajustement nécessaires dans la fonction. Un petit bout de pseudo-code vous a été fourni, complétez le pseudo-code puis implémentez le code Python.

#POUR CHAQUE degat DANS liste_degats FAIRE
#    Réduire points_vie_victime de la valeur de degats.
#    <<... Compléter le pseudo-code ....>>
#
#Fin pour
  • N'oubliez pas d'ajuster la description du docstring de la fonction.

Solution

[Dans ce qui suit, je vous donne une solution générale au problème. Il est possible que le programme proposé ne soit pas complet, qu'il ne traite pas tous les cas limites, etc. Vous devez vous assurer du bon fonctionnement de votre programme selon tous les critères vus depuis le début de la session (traitement des exceptions, cas limites, validation de données, etc.).]

def attaquer(nom_attaquant:str, nom_victime:str, degats:list, points_vie_victime:int):
    """
    Cette fonction effectue plusieurs attaques successives d'un personnage contre un autre,
    réduit les points de vie de la victime, et affiche le résultat de
    l'attaque.

    :param nom_attaquant: Le nom de l'attaquant.
    :param nom_victime: Le nom de la victime.
    :param degats: Liste de points de dégâts infligés à la victime.
    :param points_vie_victime: Les points de vie actuels de la victime avant l'attaque.
    :return: Les points de vie de la victime après l'attaque.
    """

    for degat in degats:
        points_vie_victime = points_vie_victime - degat
        print(f"{nom_attaquant} attaque ! {nom_victime} perd {degat} points de vie.")
        print(f"Points de vie du {nom_victime} : {points_vie_victime}")
        if points_vie_victime <= 0:
            print(f"{nom_victime} est vaincu !")
            break

    return points_vie_victime

if __name__ == "__main__":
    # Points de vie initiaux
    points_vie_chevalier = 100
    points_vie_dragon = 120

    liste_degats = [40, 80, 20]
    points_vie_dragon = attaquer("chevalier", "dragon", liste_degats, points_vie_dragon)

Fonctionnalité : attaques à tour de rôle

Vous devez mettre à jour votre programme afin d'avoir un combat à tour de rôle où l'utilisateur spécifie à chaque tour quel personnage est l'attaquant. La combat s'arrête lorsque l'un des deux est vaincu et on doit afficher qui est vaincu.

Lorsque l'utilisateur se trompe d'attaquant (ni chevalier, ni dragon), on doit le mettre au courant en lui affichant un message.

Pour l'instant, définissez deux listes différentes de dégâts pour chaque attaquant. Nous ajouterons la fonctionnalité de génération aléatoire de la liste de dégâts plus tard.

Peut vous servir dans votre programme :

  • Pour transformer une chaîne de caractères ma_chaine entièrement en minuscules ma_chaine.lower()

  • Pour supprimer les espaces qui entourent une chaîne de caractères ma_chaine : ma_chaine.strip()

  • Pour faire les deux ma_chaine.strip().lower()

Questions à se poser (indices)
  • Ai-je besoin d'une nouvelle fonction? Si oui, quel serait son nom? ses paramètres ?

  • Comment faire pour avoir plusieurs tours durant le combat ? Quelle est la structure logique approprié pour le faire ?

  • À quel moment s'arrête le combat ? Comment interpréter "La combat s'arrête lorsqu'un des deux est vaincu" en condition d'arrêt ?

Solution

[Dans ce qui suit, je vous donne une solution générale au problème. Il est possible que le programme proposé ne soit pas complet, qu'il ne traite pas tous les cas limites, etc. Vous devez vous assurer du bon fonctionnement de votre programme selon tous les critères vus depuis le début de la session (traitement des exceptions, cas limites, validation de données, etc.).]

Ici, je montre uniquement la nouvelle fonction créée et le programme principal qui a changé :

def combat_tour_par_tour(points_vie_chevalier: int, points_vie_dragon: int):
    """
    Fonction qui permet de simuler un combat à tour de rôle entre le chevalier et le dragon.
    L'utilisateur spécifie qui attaque à chaque tour, et le combat continue jusqu'à ce que
    l'un des deux personnages soit vaincu.

    :param points_vie_chevalier: Points de vie initiaux du chevalier.
    :param points_vie_dragon: Points de vie initiaux du dragon.
    """

    while points_vie_chevalier > 0 and points_vie_dragon > 0:
        attaquant = input("Qui doit attaquer ? (chevalier/dragon): ").strip().lower()

        if attaquant == "chevalier":
            liste_degats_chevalier = [10, 20, 30]
            points_vie_dragon = attaquer("chevalier", "dragon", liste_degats_chevalier, points_vie_dragon)

        elif attaquant == "dragon":
            liste_degats_dragon = [15, 25, 35]
            points_vie_chevalier = attaquer("dragon", "chevalier", liste_degats_dragon, points_vie_chevalier)

        else:
            print("Saisie invalide, veuillez entrer 'chevalier' ou 'dragon'.")

        if points_vie_chevalier <= 0:
            print("Le chevalier est vaincu !")
        elif points_vie_dragon <= 0:
            print("Le dragon est vaincu !")

if __name__ == "__main__":
    # Points de vie initiaux
    pv_chevalier = 100
    pv_dragon = 120

    combat_tour_par_tour(pv_chevalier, pv_dragon)

Débogage

La fonction evaluer_combat simule un combat entre un attaquant et une victime en prenant en compte plusieurs facteurs qui influencent l'issue de l'attaque.

  • Effectuer des attaques puissantes qui infligent à la victime le double des dégâts. Les dégâts sont réduits lorsque la victime à un bouclier (augmentés que de 50%).

  • L'attaquant est déclaré trop faible pour continuer lorsque ses points de vie atteignent 30.

  • Plusieurs attaques successives sont faites tant que les personnages sont en état de santé.

Votre travail est

  • d'utiliser le débogueur pour déboguer une fonction qui évalue le résultat d'une attaque,

  • d'expliquer brièvement votre raisonnement lorsque vous avez trouvé un bogue à l'aide du débogueur,

  • de corriger le bogue.

  • d'archiver et pousser chacune de vos corrections de bogue dans GitLab avec un beau message de commit.

Points de vie attaquant
Points de vie victime
Attaque puissante
Bouclier victime
Résultat attendu
Résultat observé
Numéro test

100

20

True

False

Victoire de l'attaquant

1

100

20

False

True

Victoire de l'attaquant

2

20

40

False

False

Défaite de l'attaquant

3

100

30

True

False

Victoire de l'attaquant

4

10

40

False

True

Défaite de l'attaquant

5

def evaluer_combat(points_vie_attaquant: int, points_vie_victime: int, attaque_puissante: bool, bouclier_victime: bool):
    """
    Cette fonction évalue l'issue d'un combat en fonction des points de vie des personnages,
    de l'utilisation d'une attaque puissante et de la présence d'un bouclier.

    :param points_vie_attaquant: Les points de vie de l'attaquant.
    :param points_vie_victime: Les points de vie de la victime.
    :param attaque_puissante: Indique si l'attaquant utilise une attaque puissante.
    :param bouclier_victime: Indique si la victime utilise un bouclier pour se protéger.
    :return: Un message indiquant le résultat du combat.
    """

    while points_vie_attaquant > 0 and points_vie_victime < 0:
        degats = 20

        if attaque_puissante:
            if bouclier_victime:
                degats = degats * 1.5
                print("Attaque puissante mais partiellement bloquée par le bouclier, dégâts augmentés de 50%.")
            else:
                degats = degats * 2
                print("Attaque puissante réussie, dégâts doublés !")
        elif bouclier_victime:
            degats = degats // 2
            print("Le bouclier de la victime réduit les dégâts de moitié.")

        if points_vie_attaquant < 10 or points_vie_victime >= 30:
            print("L'attaquant est trop faible pour continuer, le combat est perdu.")
            return "Défaite de l'attaquant"

        if points_vie_victime <= 0:
            print(f"La victime a {points_vie_victime} points de vie restants. Elle est vaincue.")
            return "Victoire de l'attaquant"

        print(f"La victime survit avec {points_vie_victime} points de vie.")

Nouvelle fonctionnalité : Potion de soin

[À suivre ...]

Fonctionnalité : générer aléatoirement la liste de dégâts

Actuellement, dans votre système de combat entre un chevalier et un dragon, les attaques sont réalisées à l'aide de listes de dégâts prédéfinies. Désormais, vous allez ajouter une nouvelle fonctionnalité qui génère automatiquement les dégâts des attaques de manière aléatoire.

[À suivre...]

Bravo! Il s'agit bien d'une fonction!

Il est possible que vous ayez à appeler la fonction qui permet de faire l'attaque (attaquer)dans votre nouvelle fonction .

🎉
😉
⭐
ici
2KB
Simulation_combat_dragon_chevalier.zip
archive