TD04 Duel de guerriers

Avant de commencer…

Consultez les corrections du TD3.

Qu’est-ce qu’on apprend

  1. Tester individuellement chaque fonction pour s’assurer qu’elle fait bien son travail.
  2. Comment utiliser des structures en C.
  3. Comment utiliser des pointeurs vers d’autres pointeurs.
  4. Comment générer des nombres aléatoires en C.

Lecture…

Entrées au clavier:


C’est l’heure du quizz…

  1. Remplissez le quizz IN102-03 avant 18h (strict).
  2. Remplissez le quizz IN102-04 avant 18h (strict).

Rappels…

Si vous rencontrez des problèmes (bugs, le programme ne marche pas, …), vous pouvez trouver des astuces sur le débogage :

  • Chapitre 18 du poly ou à la fin du notebook IN102-12 En cas de besoin, rafraichissez votre mémoire sur les sujets suivants.

Pointeurs:


Au boulot…

Vous allez programmer un jeu de duel entre deux guerriers terribles : Aragorn et Boromir. Les deux jouent au tour par tour, en commençant par Aragorn. Le joueur actif peut

  • soit attaquer pour retirer des points de vie de l’adversaire selon sa force d’attaque,
  • soit lever son bouclier, pour récupérer des points de vie en fonction de son taux de guérison.

Puisque ce programme a déjà une certaine complexité, il est important de bien découper le projet en petits morceaux et d’implémenter un morceau à la fois.

A chaque étape, testez bien votre vos fonctions: appelez la fonction depuis le main avec des arguments fictifs, puis affichez le résultat pour vérifier le bon fonctionnement. Ne sautez pas des étapes, demandez de l’aide si besoin.

Attention: Pour chaque réponse il suffit d’inclure les lignes de code qui sont pertinentes.

IMPORTANT: Donnez votre prénom et nom au début du fichier de réponse, sous forme de commentaire. Ajoutez également les réponses aux questions dans votre programme, sous forme de commentaires. Exemple:

/* Jeanne LAGAFFE */
#include <stdio.h>
int main () {
   printf("Hello World !!\n");
}
/* 
Q1: Ceci est la réponse à la question 1.
Q2: Voilà la réponse à la question 2.
*/

Q1:

Un guerrier a

  • un nom,
  • des points de vie (0…100),
  • des points d’attaque (0…100) et
  • un taux de guérison (0…1).

Les points de vie et le taux de guérison sont des valeurs réelles, les points d’attaque sont des entiers. Définir un struct guerrier pour stocker ces valeurs.

Astuce: pour le nom, utilisez char* nom;

Q2:

Dans le main, définir deux guerriers : Aragorn a 20 points d’attaque et un taux de guérison de 0.6. Boromir a 30 points d’attaque et un taux de guérison de 0.4. Les deux démarrent avec 100 points de vie.

Astuce: Pour définir le nom, pensez bien à utiliser des guillemets doubles (").

Q3:

Définissez une fonction

void afficher_guerrier(struct guerrier g)

qui affiche le nom et les points de vie d’un guerrier. Pour tester votre struct, utilisez cette fonction pour afficher les deux guerriers dans le main.

Q4:

Définissez une fonction

void attaque(struct guerrier* pjoueur, struct guerrier* padversaire)

qui prend en argument deux guerriers (le joueur et son adversaire) et qui diminue les points de vie de l’adversaire par les points d’attaque du joueur. Testez cette fonction dans le main et vérifiez qu’elle produit le bon nombre de points pour les deux joueurs. Pourquoi on utilise ici les pointeurs ?

Q5:

Définissez une fonction

void bouclier(struct guerrier* pjoueur)

qui ajuste les points du joueur selon la formule

points de vie ← points de vie + taux de guérison × (100 − points de vie).

Testez cette fonction dans le main et vérifiez qu’elle produit le bon nombre de points pour les deux joueurs.

Q6:

A chaque tour, il faudra échanger les joueur et l’adversaire. Vous allez utiliser une solution élégante qui s’appuie sur les pointeurs. Définissez deux pointeurs, un pour le joueur et un pour l’adversaire :

struct guerrier∗ pjoueur ;
struct guerrier∗ padversaire ;

Au début, pjoueur pointe vers Aragorn et padversaire vers Boromir. Ajoutez dans votre main une boucle, dont chaque tour correspond à un tour du jeu (un seul joueur fait son jeu). A chaque tour, on échange les valeurs des deux pointeurs. Pour tester, ne faites d’abord que des attaques et affichez le joueur et l’adversaire pour bien vérifier qu’ils jouent en alternance.

Q7:

Ajoutez maintenant un appel vers scanf pour récupérer une touche du clavier et lancer l’action en fonction. Si la touche est a, le joueur attaque, si c’est b, il lève son bouclier.

Astuce : Pour des raisons techniques, le terminal impose de taper Entrée après chaque touche. Utilisez

scanf(" %c",&touche)

pour éviter des problèmes. L’espace avant le %c dit à scanf d’ignorer le white space (retour à la ligne, espaces, tabulations). Si on ne le met pas, scanf va considerer aussi Entrée comme une touche.

Q8:

Ajoutez un pointeur nommé gagnant qui vaut 0 au départ :

struct guerrier* gagnant = 0;

Quand les points de vie de l’adversaire sont inférieur ou égal à zéro, pointez gagnant vers le guerrier qui a gagné. Utilisez ce pointeur pour arrêter la boucle quand quelqu’un a gagné, puis pour afficher le nom du guerrier vainqueur. Affichez également le nombre de tours joués.

Q9:

Est-il possible pour Aragon de jouer sans fin, même si Boromir joue les meilleures actions possibles? Peut-il toujours gagner?

Q10:

Pour que le jeu devienne imprévisible, ajoutez après chaque tour un nombre de points de vie à l’adversaire. Ce nombre doit être aléatoire dans l’intervalle [−5, 5]. Pour cela, écrivez d’abord une fonction rand_int qui prend en argument un entier p et donne un entier aléatoire dans l’intervalle [−p, p].

Astuce : On peut obtenir un entier aléatoire entre 0 et x avec l’instruction

rand()%(x+1)

La fonction rand se trouve dans stdlib.h. Pour que rand génère une séquence différente à chaque jeu, on peut l’amorcer avec l’horloge actuel. Pour cela, appelez au début de votre programme (dans le main) l’instruction

srand(time(0));

La fonction time est définie dans time.h.

Validez:

Nommez le fichier T04.c et envoyez-le à votre chargé de TD