Sujet exam (Janvier 2020)

Contexte : le jeu Pokémon

L’objectif de ce sujet d’examen est d’arriver à coder une version simplifiée d’un jeu Pokémon. Dans cette version simplifiée de Pokémons, il n’existera que 3 types : Feu, Eau et Plante. Dans notre version, un Pokémon possède en plus de son type, une valeur d’attaque, des points de vie, un niveau et un montant d’expérience.

Questions

Pour chaque question, n’hésitez pas à réutiliser les fonctions déjà créées. Si vous n’avez pas réussi à créer la fonction d’un exercice précédent, vous pouvez la réutiliser quand même comme si vous l’aviez codée.

Affichage du statut (6 pts)

Q1. Créer une fonction afficheStatut qui prend en paramètre le nom du Pokémon et ses statistiques (type, attaque, niveau, points de vie et expériences), sous la forme (1 point) :

Salamèche [Feu]
Attaque : 10
Niveau : 2
Vie : 40 / 40
Exp : 15 / 20

Le montant total de point de vie est égal à 20 * niveau et le montant total de points d’expérience nécessaire pour gagner un niveau est égal à 10 * Niveau. Dans l’exemple ci-dessus, Salamèche est au niveau 2, il a donc 20 * 2 = 40 points de vie et il lui faut donc 10 * 2 = 20 points d’expérience pour monter au niveau 3.

def afficheStatut(nom, type, atk, niv, vie, exp):
    print(nom, "[",type,"]")
    print("Attaque : ", atk)
    print("Niveau : ", niv)
    print("Vie : ", vie, "/", 20 * niv)
    print("Exp : ", exp, "/", 10 * niv)

[comment]

Q2. Donner le code nécessaire pour appeler la fonction précédente, avec le Pokémon Salamèche, 10 en attaque, niveau 2, 40 de vie et 15 points d’expériences (0.5 points)

[comment]

afficheStatut("Salamèche", "Feu", 10, 2, 40,15)

Q3.(a) Créer une fonction afficheJauge qui prend en paramètre une valeur et un montant total et affiche un [, autant de # que la valeur, complète avec des _ pour arriver au montant total, puis se termine par un ]. (2 points)

Pour une valeur de 15 et un montant total de 20 :
[###############_____] (15/20)
Pour une valeur de 15 et un montant total de 30 :
[###############_______________] (15/30)

Note: Vous pouvez éviter le retour à la ligne du print par défaut grâce au paramètre end comme dans l’exemple suivant :

print("test ",end="")
print("cela écrit à la ligne",end="\n")
print("maintenant on revient à une nouvelle ligne")

Donne le résultat suivant:

testcela écrit à la ligne
maintenant on revient à une nouvelle ligne
def afficheJauge(valeur, total):
    print("[", end="")
    print("#" * valeur, end="")
    print("_" * total, end ="")
    print("]", end="")
    print("(",valeur,"/",total,")")

Q3.(b) A la question précédente, la jauge n’a pas la même taille en fonction des différentes valeurs. Pour résoudre ce problème, nous allons fixer la taille maximale de la jauge à 50. Pour connaitre le nombre de # à mettre, il faut faire le calcul suivant : (valeur * 50) / (montant max). Modifier la fonction précédente pour avoir exactement 50 caractères. (1 point)

Pour une valeur de 15 et un montant total de 20 :
(15 * 50) / 20 = 38 (on a donc 38 # sur 50)
[######################################____________] (15/20)
Pour une valeur de 15 et un montant total de 20 :
(15 * 50) / 30 = 25 (on a donc 25 # sur 50)
[#########################_________________________] (15/30)
def afficheJauge(valeur, total):
    print("[", end="")
    dieses = int((valeur * 50) / (total))
    print("#" * dieses, end="")
    print("_" * (50 - dieses), end ="")
    print("]", end="")
    print("(",valeur,"/",total,")")

Q4. Créer une fonction afficheStatutV2 qui prend en paramètre le nom du Pokémon et ses statistiques, et réutilise certaine(s) fonction(s) codées précédemment pour afficher le résultat sous la forme suivante (1.5 point) :

Salamèche [Feu]
Attaque : 10
Niveau : 2
Vie : [##################################################] (40/40)
Exp : [######################################____________] (15/20)
def afficheStatut(nom, type, atk, niv, vie, exp):
    print(nom, "[",type,"]")
    print("Attaque : ", atk)
    print("Niveau : ", niv)
    print("Vie : ", end="")
    afficheJauge(vie, 20 * niv)
    print("Exp : ", end="")
    afficheJauge(exp, 10 * niv)

Choix du Pokémon et évolution (6 points)

Rappel: Pour certaines questions, vous pouvez utiliser la fonction random.randinit(min, max). Par exemple, random.randint(1,6) vous donne le résultat d’un lancer de dé à 6 faces.

Q5. Donner le code pour créer 6 variables nom, type, attaque, niveau, vie et experience. Le nom et le type du Pokémon vaut au départ la chaîne de caractères vide "" (on ne sait pas encore quel sera le Pokémon, ni son type), l’attaque et la vie est un nombre aléatoire entre 5 et 15, le niveau vaut 1 et l’expérience de départ est à 0. (1 point)

On supposera les 5 variables ci-dessus accessibles en tout temps dans le programme.

nom = ""
type = ""
attaque = randint(5,15)
vie = randint(5,15)
niveau = 1
experience = 0

Q6. Choix du starter : Donner le code nécessaire pour demander au joueur quel type de Pokémon il veut au départ et affiche le bon message suivant son choix:

Quel type de Pokémon voulez vous ? [Feu/Eau/Plante]
C'est un [Nom du Pokémon] !

[Nom du Pokémon] vaut Salamèche si le type est Feu, Carapuce si le type est Eau, et Bulbizarre sinon. Vous modifierez en conséquence la valeur des variables nom et type (2 points)

Note: Le mot-clé global n’était pas attendu, vu qu’on suppose que les variables externes soient accessibles en tout temps.

def choixStarter():
    global type
    types_possibles = ["Feu", "Eau", "Plante"]
    while type not in types_possibles:
        type = input("Quel type de Pokémon voulez vous " + str(types_possibles) + " ? ")
    if type == "Feu":
        nom = "Salamèche"
    elif type == "Eau":
        nom = "Carapuce"
    else:
        nom = "Bulbizarre"

Q7. Gain expérience : Créer une fonction ajout_exp(montant) qui ajoute autant de points d’expérience au Pokémon que la valeur de montant et qui a le comportement suivant (3 points) :

  • Si experience > 10 * niveau alors :
    • on enlève 10 * niveau points d’expérience, le Pokémon gagne 1 niveau et son attaque augmente d’une valeur aléatoire comprise entre 5 et 10.
  • Si le Pokémon gagne un niveau ET niveau = 16 alors : le Pokémon évolue :
    • Si c’est un Salamèche, alors il devient Reptincel
    • Si c’est un Carapuce, alors il devient Carabaffe
    • Si c’est un Bulbizarre, alors il devient Herbizarre
def ajout_exp(montant):
    global experience, niveau, nom, attaque
    experience = experience + montant
    if experience > 10 * niveau:
        niveau = niveau + 1
        attaque = attaque + randint(5,10)
        if niveau == 16:
            if nom == "Salamèche":
                nom = "Reptincel"
            elif nom == "Carapuce":
                nom = "Carabaffe"
            else:
                nom = "Herbizarre"

Combat de Pokémon (9 points)

Q8. Créer une fonction type_au_hasard() qui retourne un type au hasard parmi Feu, Plante et Eau. Pour réaliser cette fonction vous pouvez tirer un nombre au hasard avec randint et retourner si c’est 1 Feu, si c’est 2 Eau, sinon Plante. (1 point)

def type_au_hasard():
    types_possibles = ["Feu", "Eau", "Plante"]
    return types_possibles[randint(0,2)]

Q9. Gestion de dégâts : Créer une fonction attaquer(type_pokemon_1, type_pokemon_2, attaque_pokemon_1) qui permet de gérer une attaque du Pokémon 1 (de type 1) sur le Pokémon 2 (de type 2) . La fonction retourne le montant de dégâts réaliser par l’attaque. Ce montant est calculé comme suit (2 points):

  • Si type_pokemon_1 == "Feu" et type_pokemon_2 == “Plante” : Afficher C'est super efficace ! et retourner comme valeur attaque_pokemon_1 * 1.5
  • Si type_pokemon_1 == "Feu" et type_pokemon_2 == “Eau” : Afficher Ce n'est pas très efficace... et retourner comme valeur attaque_pokemon_1 * 0.5
  • Dans les autres cas : retourner comme valeur attaque_pokemon

Note: Pour simplifier (et gagner du temps), nous gérons uniquement les affinités du Feu vers les autres types, mais vous avez l’idée pour les autres comparaisons ;) .

def attaquer(type_pokemon_1, type_pokemon_2, attaque_pokemon_1):
    if type_pokemon_1 == "Feu" and type_pokemon_2 == "Plante":
        print("C'est super efficace !'")
        return attaque_pokemon_1 * 1.5
    elif type_pokemon_1 == "Feu" and type_pokemon_2 == "Eau":
        print("Ce n'est pas très efficace'")
        return attaque_pokemon_1 * 0.5
    else:
        return attaque_pokemon_1

Q10. Combat ! Créer une fonction combat(type_adv, attaque_adv, niveau_adv) où les paramètres concernent les statistiques du Pokémon à combattre. Cette fonction a le comportement suivant (4 points):

  1. Le Pokémon adverse a tous ses points de vie au début (20 * niveau_adv).
  2. Votre Pokémon attaque le Pokémon adverse, le Pokémon adverse perd des points de vie égaux au montant de la fonction attaquer
  3. Si le Pokémon adverse a encore des PV, le Pokémon adverse vous attaque, vous perdez des points de vie égaux au montant de la fonction attaquer. Sinon si le Pokémon n’a plus de PV (PV <= 0) afficher Vous avez gagné ! et retourner True
  4. Si vous avez encore des points de vie, retour au point 2. Sinon afficher Vous avez Perdu ! et retourner False
def combat(type_adv, attaque_adv, niveau_adv):
    global vie
    pv_pokemon_adv = niveau_adv * 20
    while pv_pokemon_adv > 0 and vie > 0:
        pv_pokemon_adv = pv_pokemon_adv - attaquer(type, type_adv, attaque)
        if pv_pokemon_adv > 0:
            vie = vie - attaquer(type_adv, type, niveau)
            if vie == 0:
                print("Vous avez Perdu !")
        else:
            print("Vous avez gagné !")

Q12. Programme complet : Écrire le programme complet suivant : (2 points)

- Choix du starter
- Initialiser les statistiques du Pokémon
TANT QUE Vie > 0 :
    - type_adv = type au hasard
    - attaque_adv = nombre aléatoire entre 10 et 15
    - niv_adv = Votre niveau + nombre aléatoire entre -2 et 2
    - Combat(type_adv, attaque_adv, niv_adv)
    - Si vous avez gagne : ajout_exp(niv_adv * 5) 
    - Afficher le statut
    
def programme():
    global experience
    choixStarter()
    while vie > 0:
        type_adv = type_au_hasard()
        attaque_adv = randint(10,15)
        niv_adv = niveau + randint(-2,2)
        combat(type_adv, attaque_adv, niv_adv)
        if vie > 0:
            experience = experience + niv_adv * 5
            afficheStatut(nom, type, attaque, niveau, vie, experience)