Aller au menu - Aller au contenu

[Plan du site] Vous êtes ici --- > Le Site du Zéro > Les tutoriels > Officiels > Programmation > Apprenez à programmer en C ! > [Théorie] Techniques avancées > TP : Réalisation d'un pendu > Lecture du tutoriel

TP : Réalisation d'un pendu

Avatar
Auteur : M@teo21
Difficulté : Connaisseur (3 / 5)
Note : 19 / 20 (51 votes)
Visualisations : 228 616

Plus d'informations Plus d'informations
Ah le pendu... Voilà un grand classique des jeux de lettres :)
Dans ce chapitre, vous allez essayer de réaliser un jeu de pendu en console en langage C.

L'objectif est de vous faire manipuler tout ce que vous avez appris dans la partie II jusqu'ici (et vous en avez appris des choses !). Au menu : pointeurs, chaînes de caractères, fichiers, tableaux... que du bon quoi !

A taaaaable ! :D
Sommaire du chapitre :
Icône du chapitre
Chapitre précédent Sommaire Chapitre suivant

Les consignes

Je veux tout d'abord qu'on se mette bien d'accord sur les règles du pendu à réaliser. Je vais donc vous donner ici les consignes, c'est-à-dire vous expliquer comment doit fonctionner le jeu que vous allez créer.

Tout le monde connaît le pendu n'est-ce pas ? Allez, un petit rappel ne peut pas faire de mal ;)
Le but du pendu est de retrouver un mot caché en moins de 10 coups (mais vous pouvez changer ce nombre maximal pour corser la difficulté bien sûr !).


Déroulement d'une partie



Supposons que le mot caché soit ROUGE.
Vous proposez une lettre à l'ordinateur, par exemple la lettre A. L'ordinateur vérifie si cette lettre se trouve dans le mot caché

Rappelez-vous : il y a une fonction toute prête dans string.h pour rechercher une lettre dans un mot ! Notez que vous n'êtes pas obligés de l'utiliser toutefois (personnellement je ne m'en suis pas servi).


A partir de là, 2 possibilités :


Dans un "vrai" pendu, il y aurait normalement un dessin d'un bonhomme qui se fait pendre au fur et à mesure que l'on fait des erreurs. Bon, comme là on travaille en console, ce serait un peu hardcore de dessiner un bonhomme qui se fait pendre rien qu'avec du texte, donc on va se contenter d'afficher une simple phrase comme "Il vous reste X coups avant une mort certaine".
Les plus courageux d'entre vous essaieront peut-être de dessiner quand même le bonhomme en console à grands coups de printf, mais je vous préviens : ce n'est pas le but du TP :D



Supposons maintenant que le joueur tape la lettre G. Celle-ci se trouve dans le mot caché, donc on ne diminue pas le nombre de coups restants pour le joueur. On affiche le mot secret avec les lettres qu'on a déjà découvertes, c'est-à-dire qu'on affiche quelque chose comme :

Code : Console
Mot secret : ***G*


Si ensuite on tape un R, comme la lettre s'y trouve, on la rajoute à la liste des lettres trouvées et on affiche le mot avec les lettres déjà découvertes :

Code : Console
Mot secret : R**G*



Le cas des lettres multiples



Dans certains mots, une même lettre peut apparaître 2, 3 fois, voire même plus !
Par exemple, il y a 2 Z dans PUZZLE
De même, il y a 3 E dans ELEMENT

Que fait-on dans un cas comme ça ? Les règles du pendu sont claires : si le joueur tape la lettre E, toutes les lettres E du mot ELEMENT doivent être découvertes d'un seul coup :

Code : Console
Mot secret : E*E*E**


Il ne faut donc pas taper 3 fois la lettre E pour que tous les E soient découverts. Ca peut paraître évident à certains d'entre vous, mais je préfère le dire avant on sait jamais :p


Exemple d'une partie complète



Voici à quoi devrait ressembler une partie complète en console de votre programme lorsqu'il sera terminé :

Code : Console
Bienvenue dans le Pendu !
 
 
 
Il vous reste 10 coups a jouer
Quel est le mot secret ? ******
Proposez une lettre : E
 
 
Il vous reste 9 coups a jouer
Quel est le mot secret ? ******
Proposez une lettre : A
 
 
Il vous reste 9 coups a jouer
Quel est le mot secret ? *A****
Proposez une lettre : O
 
 
Il vous reste 9 coups a jouer
Quel est le mot secret ? *A**O*
Proposez une lettre : P
 
 
Il vous reste 8 coups a jouer
Quel est le mot secret ? *A**O*
Proposez une lettre : M
 
 
Il vous reste 8 coups a jouer
Quel est le mot secret ? MA**O*
Proposez une lettre : N
 
 
Il vous reste 8 coups a jouer
Quel est le mot secret ? MA**ON
Proposez une lettre : R
 
 
Gagne ! Le mot secret etait bien : MARRON



Saisie d'une lettre en console



La lecture d'une lettre dans la console est plus compliquée qu'il n'y paraît.
Intuitivement, pour récupérer un caractère, vous devriez avoir pensé à :

Code : C
1
scanf("%c", &maLettre);


Et effectivement, c'est bien. %c indique que l'on attend un caractère, qu'on stockera dans maLettre (une variable de type char).

Tout se passe très bien... tant qu'on ne refait pas un scanf. En effet, vous pouvez tester le code suivant :

Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
int main(int argc, char* argv[])
{
     char maLettre = 0;
 
     scanf("%c", &maLettre);
     printf("%c", maLettre);
 
     scanf("%c", &maLettre);
     printf("%c", maLettre);
 
     return 0;
}


Normalement, ce code est censé vous demander une lettre et vous l'afficher, et cela 2 fois.
Testez. Que se passe-t-il ? Vous rentrez une lettre d'accord mais... le programme s'arrête de suite après, il ne vous demande pas la seconde lettre ! On dirait qu'il ignore le second scanf.

Que s'est-il passé ?


En fait, quand vous rentrez du texte en console, tout ce que vous tapez est stocké quelque part en mémoire, y compris l'appui sur la touche Entrée (\n).

Ainsi, la première fois que vous rentrez une lettre (par exemple A) puis que vous tapez Entrée, c'est la lettre A qui est renvoyée par le scanf. Mais la seconde fois, scanf renvoie le \n correspondant à la touche "Entrée" que vous aviez tapée auparavant !


Oulah, comment éviter cela ?


Le mieux, c'est de créer notre propre petite fonction lireCaractere() :

Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
char lireCaractere() 
{ 
    char caractere = 0;
 
    caractere = getchar(); // On lit le premier caractère
    caractere = toupper(caractere); // On met la lettre en majuscule si elle ne l'est pas déjà
 
    // On lit les autres caractères mémorisés un à un jusqu'à l'\n (pour les effacer) 
    while (getchar() != '\n') ;
 
    return caractere; // On retourne le premier caractère qu'on a lu
 
}



Cette fonction utilise getchar() qui est une fonction de stdio identique à scanf("%c", &lettre);. La fonction getchar renvoie le caractère que le joueur a tapé.
Après, j'utilise une fonction standard qu'on n'a pas eu l'occasion d'étudier dans le cours : toupper(). Cette fonction transforme la lettre indiquée en majuscule. Comme ça, le jeu fonctionnera même si le joueur tape des lettres minuscules. Il faut inclure ctype.h pour pouvoir utiliser cette fonction (ne l'oubliez pas !)

Ensuite vient la partie la plus intéressante : celle où je vide les autres caractères qui auraient pu avoir été tapés. En effet, en refaisant un getchar on prend le caractère suivant que l'utilisateur a tapé (par exemple l'Entrée \n).
Ce que je fais est simple et tient en une ligne : j'appelle la fonction getchar en boucle jusqu'à tomber sur le caractère \n. La boucle s'arrête dès qu'on tombe sur l'\n, ce qui signifie qu'on a "lu" tous les autres caractères de la mémoire, ils ont donc été vidés de la mémoire. On dit qu'on vide le buffer.

Euh pourquoi il y a un point-virgule à la fin du while et pourquoi il n'y a pas d'accolades ?

En fait, je fais une boucle qui ne contient pas d'instructions (la seule instruction c'est le getchar entre les parenthèses). Les accolades ne sont pas nécessaires vu que je n'ai rien d'autre à faire qu'un getchar. Je mets donc un point-virgule pour remplacer les accolades. Ce point-virgule signifie "ne rien faire à chaque passage dans la boucle". C'est un peu particulier je le reconnais, mais c'est une technique à connaître qu'utilisent les programmeurs pour faire des boucles très courtes et très simples.

Pour mieux comprendre, dites vous que le while aurait aussi pu être écrit comme ceci :

Code : C
1
2
3
4
while (getchar() != '\n') 
{
 
}


Il n'y a rien entre accolades c'est volontaire, vu qu'on n'a rien d'autre à faire. Ma technique de placer juste un point-virgule est plus courte que celle avec des accolades, c'est tout ;)


Enfin, la fonction lireCaractere retourne le premier caractère qu'elle a lu (la variable caractere).


En résumé : pour récupérer une lettre dans votre code, vous n'utiliserez pas :
Code : C
1
scanf("%c", &maLettre);

Mais vous utiliserez à la place notre super fonction :
Code : C
1
maLettre = lireCaractere();




Dictionnaire de mots



Dans un premier temps pour vos tests, je vais vous demander de fixer le mot secret directement dans votre code. Vous écrirez donc par exemple :

Code : C
1
char motSecret[] = "MARRON";


Alors oui, bien sûr le mot secret sera toujours le même si on laisse ça comme ça, ce qui n'est pas très rigolo :p
Je vous demande de faire comme ça dans un premier temps pour ne pas mélanger les problèmes. En effet, une fois que votre jeu de pendu fonctionnera correctement (et seulement à partir de ce moment-là) vous attaquerez la 2ème phase : la création du dictionnaire de mots.

Qu'est-ce que c'est le "dictionnaire de mots" ?


C'est un fichier qui contiendra plein de mots pour votre jeu de pendu. Il doit y avoir un mot par ligne. Exemple :

Code : Console
MAISON
BLEU
AVION
XYLOPHONE
ABEILLE
IMMEUBLE
GOURDIN
NEIGE
ZERO


A chaque nouvelle partie, votre programme devra ouvrir ce fichier et prendre un des mots au hasard dans la liste. Grâce à cette technique, vous aurez un fichier à part que vous pourrez éditer tant que vous voudrez pour ajouter des mots secrets possibles pour le pendu :)

Vous aurez remarqué que depuis le début je fais exprès de mettre tous mes mots en majuscule. En effet, dans le pendu on ne fait pas la distinction entre les majuscules et les minuscules, donc le mieux est de se dire dès le début : "tous mes mots seront en majuscules". A vous de prévenir le joueur (dans le mode d'emploi du jeu par exemple) qu'il est censé rentrer des lettres majuscules et non des minuscules
Par ailleurs, on fait exprès d'ignorer les accents pour simplifier (si on doit commencer à tester le é, le è, le ê, le ë... on n'a pas fini :p ). Vous devrez donc écrire vos mots dans le dictionnaire entièrement en majuscules et sans accents.


Le problème qui se posera rapidement pour vous sera de savoir combien il y a de mots dans le dictionnaire. En effet, si vous voulez choisir un mot au hasard, il faudra tirer au sort un nombre entre 0 et X, et vous ne savez pas combien de mots contient votre fichier à priori.
Pour résoudre le problème, 2 solutions :



Je vous laisse réfléchir un peu là-dessus, je vais pas trop vous aider quand même sinon ça sera plus un TP :p
Sachez que vous avez acquis toutes les connaissances qu'il faut dans les chapitres précédents, donc vous êtes parfaitement capables de réaliser ce jeu. Ca va prendre plus ou moins de temps et c'est moins facile qu'il n'y paraît, mais en vous organisant correctement (et en créant suffisamment de fonctions) vous y arriverez ;)

Bon courage, et surtout : per-sé-vé-rez !

La solution (1 : le code du jeu)

Si vous lisez ces lignes, c'est soit que vous avez terminé le programme, soit... que vous n'arrivez pas à le terminer ;)

J'ai personnellement mis plus de temps que je ne le pensais pour réaliser ce petit jeu apparemment tout bête. C'est souvent comme ça : on se dit "boah c'est facile" alors qu'en fait il y a plein de cas à gérer ;)
Je persiste toutefois à dire que vous êtes tous capables de le faire. Il vous faudra plus ou moins de temps (quelques minutes, quelques heures, quelques jours ?), mais ça n'a jamais été une course. Je préfère que vous y passiez beaucoup de temps et que vous y arriviez, plutôt que vous n'essayiez que 5 minutes et que vous regardiez la solution.

Rappelez-vous que c'est précisément dans les TP que le gros du travail se fait : la pratique, c'est vraiment pas la même chose que la théorie :D
C'est donc principalement pendant les TP que vous progressez, raison de plus pour y mettre tous vos efforts ;)


N'allez pas croire que j'ai écrit le programme d'une traite. Moi aussi, comme vous, j'y suis allé pas à pas. J'ai commencé par faire quelque chose de très simple, puis petit à petit j'ai amélioré le code pour finalement arriver au résultat final :)
J'ai fait plusieurs erreurs en codant : j'ai oublié à un moment d'initialiser une variable correctement, j'ai oublié de mettre un prototype de fonction ou encore de supprimer une variable qui ne servait plus dans mon code. J'ai même, je l'avoue, oublié un bête point-virgule à un moment à la fin d'une ligne.

Tout ça pour dire quoi ? Que je ne suis pas infaillible et que je vis à peu près les mêmes frustrations que vous : "ESPECE DE PROGRAMME DE ***** TU VAS TE METTRE A MARCHER OUI OU NON !?".

Je vais vous présenter la solution en 2 temps :
  1. D'abord je vais vous montrer comment j'ai fait le code du jeu lui-même, en fixant le mot caché directement dans le code (j'ai pris le mot MARRON car il me permet de tester si je gère bien les lettres en double comme R ici).
  2. Ensuite, je vous montrerai comment dans un second temps j'ai ajouté la gestion du dictionnaire de mots pour tirer au sort un mot secret pour le joueur.


Bien sûr, je pourrais vous montrer tout le code d'un coup mais... ça ferait beaucoup à la fois, et nombre d'entre vous n'auraient pas le courage de se pencher dans le code (je suis comme vous, quand y'a un gros code à comprendre je mets plus de temps que pour un petit code :D )


Je vais essayer de vous expliquer pas à pas mon raisonnement. Ce qui compte, ce n'est pas le résultat, mais la façon dont on réfléchit.

Analyse de la fonction main



Comme tout le monde le sait, tout commence par un main. On n'oublie pas d'inclure les librairies stdio, stdlib et ctype (pour la fonction toupper()) dont on aura besoin :

Code : C
1
2
3
4
5
6
7
8
9
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

int main(int argc, char* argv[])
{

    return 0;
}


Ok, jusque là tout le monde devrait suivre :D
Notre main va gérer la plupart du jeu et faire appel à 2-3 de nos fonctions quand il en aura besoin.

Commençons par déclarer les variables dont on va avoir besoin. Rassurez-vous, je n'ai pas pensé de suite à toutes ces variables, il y en avait un peu moins la première fois que j'ai écrit le code ;)

Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

int main(int argc, char* argv[])
{
    char lettre = 0; // Stocke la lettre proposée par l'utilisateur (retour du scanf)
    char motSecret[] = "MARRON"; // C'est le mot à trouver
    int lettreTrouvee[6] = {0}; // Un tableau de booléens. Chaque case correspond à une lettre du mot secret. 0 = lettre non trouvée, 1 = lettre trouvée
    long coupsRestants = 10; // Compteur de coups restants (0 = mort)
    long i = 0; // Une petite variable pour parcourir les tableaux

    return 0;
}


J'ai fait exprès de mettre une déclaration de variable par ligne ainsi que pas mal de commentaires pour que vous compreniez. En pratique, vous n'aurez pas forcément besoin de mettre tous ces commentaires, et vous pourrez grouper plusieurs déclarations de variables sur la même ligne.

Je pense que la plupart de ces variables semblent logiques : la variable lettre stocke la lettre que l'utilisateur tape à chaque fois, le motSecret c'est le mot à trouver, coupsRestants le nombre de coups etc.
La variable i est une petite variable que j'utilise pour parcourir mes tableaux avec des for. Elle n'est donc pas extrêmement importante mais elle est nécessaire si on veut faire nos boucles.

Enfin, la variable à laquelle il fallait penser, celle qui fait la différence, c'est mon tableau de booléens lettreTrouvee. Vous remarquerez que je lui ai donné pour taille le nombre de lettres du mot secret (6). Ce n'est pas un hasard : chaque case de ce tableau de booléens représente une lettre du mot secret. Ainsi, la première case représente la première lettre, la seconde case représente la seconde lettre etc.
Les cases du tableau sont au départ initialisées à 0, ce qui signifie "Lettre non trouvée". Au fur et à mesure de l'avancement du jeu, ce tableau sera modifié. Pour chaque lettre du mot secret trouvée, la case correspondante du tableau lettreTrouvee sera mise à 1.

Par exemple, si à un moment du jeu j'ai l'affichage suivant : M*RR*N, c'est que mon tableau d'int a les valeurs : 101101 (1 pour chaque lettre qui a été trouvée).
Il est ainsi facile de savoir quand on a gagné : il suffit de vérifier si le tableau de booléens ne contient que des 1.
En revanche, on a perdu si le compteur coupsRestants tombe à 0.

Passons à la suite :

Code : C
1
printf("Bienvenue dans le Pendu !\n\n");


Bon, ça c'est un message de bienvenue, j'ai rien à ajouter :D

Ensuite, on commence la boucle principale du jeu :

Code : C
1
2
while (coupsRestants > 0 && !gagne(lettreTrouvee))
{


Le jeu continue tant qu'il reste des coups (coupsRestants > 0) et tant qu'on n'a pas gagné.
Si on n'a plus de coups à jouer, c'est qu'on a perdu. Si on a gagné, c'est... qu'on a gagné ^^

"gagne" est une fonction qui analyse le tableau lettreTrouvee. Elle renvoie vrai (1) si le joueur a gagné (le tableau lettreTrouvee ne contient que des 1), faux (0) si le joueur n'a pas encore gagné.
Je ne vous explique pas le fonctionnement de cette fonction en détail pour le moment. On verra cela plus tard. Pour le moment, vous avez juste besoin de savoir ce que fait la fonction.

La suite :

Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
printf("\n\nIl vous reste %ld coups a jouer", coupsRestants);
printf("\nQuel est le mot secret ? ");

/* On affiche le mot secret en masquant les lettres non trouvées
        Exemple : *A**ON */
        for (i = 0 ; i < 6 ; i++)
        {
            if (lettreTrouvee[i]) // Si on a trouvé la lettre n°i
                printf("%c", motSecret[i]); // On l'affiche
            else
                printf("*"); // Sinon, on affiche une étoile pour les lettres non trouvées
        }



On affiche à chaque coup le nombre de coups restants ainsi que le mot secret (masqué par des * pour les lettres non trouvées).
L'affichage du mot secret masqué par des * se fait grâce à une boucle for. On analyse pour chaque lettre si elle a été trouvée (if lettreTrouvee[i]). Si c'est le cas, on affiche la lettre. Sinon, on affiche une * de remplacement pour masquer la lettre.


Maintenant qu'on a affiché ce qu'il fallait, on va demander au joueur de saisir une lettre :

Code : C
1
2
printf("\nProposez une lettre : ");
lettre = lireCaractere();


Je fais appel à notre fonction lireCaractere(). Celle-ci lit le premier caractère tapé, le met en majuscule et vide le buffer (c'est-à-dire qu'elle vide les autres caractères qui auraient pu être restés dans la mémoire).


Code : C
1
2
3
4
5
6
// Si ce n'était PAS la bonne lettre
        if (!rechercheLettre(lettre, motSecret, lettreTrouvee))
        {
            coupsRestants--; // On enlève un coup au joueur
        }
    }


On teste si la lettre entrée se trouve dans motSecret. On fait appel pour cela à une fonction maison appelée rechercheLettre. Nous verrons peu après le code de cette fonction.
Pour le moment, tout ce que vous avez besoin de savoir, c'est que cette fonction renvoie "vrai" si la lettre se trouve dans le mot, "faux" si elle ne s'y trouve pas.

Mon if, vous l'aurez remarqué, commence par un point d'exclamation "!" qui signifie "non". La condition se lit donc "Si la lettre n'a pas été trouvée".
Que fait-on si la lettre n'a pas été trouvée ? On diminue le nombre de coups restants.

Notez que la fonction rechercheLettre met aussi à jour le tableau de booléens lettreTrouvee. Elle met des 1 dans les cases des lettres qui ont été trouvées.


La boucle principale du jeu s'arrête là. On recommence donc au début de la boucle et on vérifie s'il reste des coups à jouer et si on n'a pas déjà gagné.


Lorsqu'on sort de la boucle principale du jeu, il reste à afficher si on a gagné ou pas avant que le programme ne s'arrête :

Code : C
1
2
3
4
5
6
7
if (gagne(lettreTrouvee))
        printf("\n\nGagne ! Le mot secret etait bien : %s", motSecret);
    else
        printf("\n\nPerdu ! Le mot secret etait : %s", motSecret);

        return 0;
}


On fait appel à la fonction "gagne" pour vérifier si on a gagné. Si c'est le cas, alors on affiche le message "Gagné !", sinon c'est qu'on n'avait plus de coups à jouer, on a été pendu.


Analyse de la fonction gagne



Voyons voir maintenant le code de la fonction gagne :

Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
int gagne(int lettreTrouvee[])
{
    long i = 0;
    int joueurGagne = 1;

    for (i = 0 ; i < 6 ; i++)
    {
        if (lettreTrouvee[i] == 0)
            joueurGagne = 0;
    }

    return joueurGagne;
}


Cette fonction prend le tableau de booléens lettreTrouvee pour paramètre. Elle renvoie un booléen : vrai si on a gagné, faux si on a perdu.

Le code de cette fonction est plutôt simple, vous devriez tous le comprendre. On parcourt lettreTrouvee et on vérifie si UNE des cases vaut faux (0). Si une des lettres n'a pas encore été trouvée, c'est qu'on a perdu : on met alors le booléen joueurGagne à faux (0). Sinon, si toutes les lettres ont été trouvée, le booléen vaut vrai (1) et la fonction renverra donc vrai.


Analyse de la fonction rechercheLettre



La fonction rechercheLettre a 2 missions :


Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
int rechercheLettre(char lettre, char motSecret[], int lettreTrouvee[])
{
    long i = 0;
    int bonneLettre = 0;

    // On parcourt motSecret pour vérifier si la lettre proposée y est
    for (i = 0 ; motSecret[i] != '\0' ; i++)
    {
        if (lettre == motSecret[i]) // Si la lettre y est
        {
            bonneLettre = 1; // On mémorise que c'était une bonne lettre
            lettreTrouvee[i] = 1; // On met à 1 le case du tableau de booléens correspondant à la lettre actuelle
        }
    }

    return bonneLettre;
}


On parcourt donc la chaîne motSecret caractère par caractère. A chaque fois, on vérifie si la lettre que le joueur a proposée est une lettre du mot. Si la lettre correspond, alors on fait 2 choses :


L'avantage de cette technique c'est qu'ainsi on parcourt tout le tableau (on ne s'arrête pas à la première lettre trouvée). Cela nous permet de bien mettre à jour le tableau lettreTrouvee, au cas où une lettre serait présente en plusieurs exemplaires dans le mot secret (comme c'est le cas pour les 2 R dans MARRON).


Pfiou !



Et voilà, on a fait le tour :D
Je résume le code source que j'utilise :

Code : C
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
/*
Jeu du pendu
Par M@teo21, pour le Site du Zér0
<lien url="www.siteduzero.com">www.siteduzero.com</lien>

main.c
------

Fonctions principales de gestion du jeu
*/

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

int gagne(int lettreTrouvee[]);
int rechercheLettre(char lettre, char motSecret[], int lettreTrouvee[]);
char lireCaractere();

int main(int argc, char* argv[])
{
    char lettre = 0; // Stocke la lettre proposée par l'utilisateur (retour du scanf)
    char motSecret[] = "MARRON"; // C'est le mot à trouver
    int lettreTrouvee[6] = {0}; // Un tableau de booléens. Chaque case correspond à une lettre du mot secret. 0 = lettre non trouvée, 1 = lettre trouvée
    long coupsRestants = 10; // Compteur de coups restants (0 = mort)
    long i = 0; // Une petite variable pour parcourir les tableaux

    printf("Bienvenue dans le Pendu !\n\n");

    // On continue à jouer tant qu'il reste au moins un coup à jouer ou qu'on
    // n'a pas gagné
    while (coupsRestants > 0 && !gagne(lettreTrouvee))
    {
        printf("\n\nIl vous reste %ld coups a jouer", coupsRestants);
        printf("\nQuel est le mot secret ? ");

        /* On affiche le mot secret en masquant les lettres non trouvées
        Exemple : *A**ON */
        for (i = 0 ; i < 6 ; i++)
        {
            if (lettreTrouvee[i]) // Si on a trouvé la lettre n°i
                printf("%c", motSecret[i]); // On l'affiche
            else
                printf("*"); // Sinon, on affiche une étoile pour les lettres non trouvées
        }

        printf("\nProposez une lettre : ");
        lettre = lireCaractere();

        // Si ce n'était PAS la bonne lettre
        if (!rechercheLettre(lettre, motSecret, lettreTrouvee))
        {
            coupsRestants--; // On enlève un coup au joueur
        }
    }


    if (gagne(lettreTrouvee))
        printf("\n\nGagne ! Le mot secret etait bien : %s", motSecret);
    else
        printf("\n\nPerdu ! Le mot secret etait : %s", motSecret);

        return 0;
}

char lireCaractere()
{
    char caractere = 0;

    caractere = getchar(); // On lit le premier caractère
    caractere = toupper(caractere); // On met la lettre en majuscule si elle ne l'est pas déjà

    // On lit les autres caractères mémorisés un à un jusqu'à l'\n
    while (getchar() != '\n') ;

    return caractere; // On retourne le premier caractère qu'on a lu
}

int gagne(int lettreTrouvee[])
{
    long i = 0;
    int joueurGagne = 1;

    for (i = 0 ; i < 6 ; i++)
    {
        if (lettreTrouvee[i] == 0)
            joueurGagne = 0;
    }

    return joueurGagne;
}

int rechercheLettre(char lettre, char motSecret[], int lettreTrouvee[])
{
    long i = 0;
    int bonneLettre = 0;

    // On parcourt motSecret pour vérifier si la lettre proposée y est
    for (i = 0 ; motSecret[i] != '\0' ; i++)
    {
        if (lettre == motSecret[i]) // Si la lettre y est
        {
            bonneLettre = 1; // On mémorise que c'était une bonne lettre
            lettreTrouvee[i] = 1; // On met à 1 le case du tableau de booléens correspondant à la lettre actuelle
        }
    }

    return bonneLettre;
}


Vous noterez que j'ai mis pour le moment les prototypes en haut du fichier, au lieu de les mettre dans un .h. C'est simplement parce que pour le moment le programme n'est pas encore bien compliqué et ne nécessite pas de créer plus que le simple fichier main.c de base.
Cependant, les choses vont changer dès qu'on attaquera la phase 2 avec la gestion du dictionnaire ;)

Il y a plein de façons différentes d'imaginer le code du jeu du pendu, aussi si vous y étiez arrivés mais avec un code complètement différent, sachez que c'est normal. Je ne dis pas que mon code est le meilleur, je dis juste que c'était une bonne façon de faire.

Comment savoir si vous avez bien fait ?
C'est simple :


La meilleure façon d'obtenir des commentaires c'est bien souvent de proposer votre code sur les forums du Site du Zér0 pour que des gens plus expérimentés puissent vous donner leur avis. N'hésitez donc pas à le faire, on apprend généralement des tas de choses comme ça ;)

La solution (2 : la gestion du dictionnaire)

Pour qu'on puisse faire des tests, la première chose à faire c'est de créer ce fameux dictionnaire de mots. Même s'il est court, c'est pas grave c'est pour les tests.

Je vais donc créer un fichier dico.txt dans le même répertoire que mon projet. Pour le moment, je mets les mots suivants :

Code : Autre
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
MAISON

BLEU

AVION

XYLOPHONE

ABEILLE

IMMEUBLE

GOURDIN

NEIGE

ZERO


Une fois que j'aurai terminé de coder le programme, je reviendrai bien sûr sur ce dictionnaire et j'y ajouterai des tooonnes de mots tordus à rallonge comme ANTICONSTITUTIONNELLEMENT :D

Mais pour le moment, retournons à nos instructions.


Préparation des nouveaux fichiers



La lecture du dico va demander pas mal de lignes de codes (du moins je le pressens :p ). Je prends donc les devants en ajoutant un nouveau fichier à mon projet : dico.c (qui sera chargé de la lecture du dico). Dans la foulée, je crée le dico.h qui contiendra les prototypes des fonctions de dico.h.

Dans dico.c, je commence par inclure les librairies dont j'aurai besoin ainsi que mon dico.h
A priori, comme souvent, j'aurai besoin de stdio et stdlib ici. En plus de cela, je vais être amené à piocher un nombre au hasard dans le dico, donc je vais inclure time.h comme on l'avait fait pour notre premier projet "Plus ou Moins" :)
Je vais aussi avoir besoin de string.h pour faire un strlen vers la fin de la fonction :

Code : C
1
2
3
4
5
6
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>

#include "dico.h"




La fonction piocherMot



Maintenant, attaquons la fonction qui va être chargée de piocher un mot au hasard dans le dictionnaire.

Cette fonction va prendre un paramètre : un pointeur sur la zone en mémoire où elle pourra écrire le mot. Ce pointeur sera fourni par le main().
La fonction renverra un int qui sera un booléen : 1 = tout s'est bien passé, 0 = il y a eu une erreur.

Voici le début de la fonction :

Code : C
1
2
3
4
5
int piocherMot(char *motPioche)
{
    FILE* dico = NULL; // Le pointeur de fichier qui va contenir notre fichier
    long nombreMots = 0, numMotChoisi = 0, i = 0;
    int caractereLu = 0;


Je définis quelques variables dont je vais avoir besoin. Comme pour le main(), je n'ai pas pensé à mettre toutes ces variables dès le début, il y en a certaines que j'ai rajoutées par la suite lorsque je me suis rendu compte que j'en avais besoin ;)

Grosso modo, les noms des variables parlent d'eux-mêmes. On a notre pointeur sur fichier dico dont on va se servir pour lire le fichier dico.txt, des variables temporaires qui vont stocker les caractères etc.
Notez que j'utilise ici un int pour stocker un caractère (caractereLu) car la fonction fgetc que je vais utiliser renvoie un int. Il est donc préférable de stocker le résultat dans un int.


Passons à la suite :

Code : C
1
2
3
4
5
6
7
8
9
dico = fopen("dico.txt", "r"); // On ouvre le dictionnaire en lecture seule

// On vérifie si on a réussi à ouvrir le dictionnaire
if (dico == NULL) // Si on n'a PAS réussi à ouvrir le fichier
{
    printf("\nImpossible de charger le dictionnaire de mots");
    return 0; // On retourne 0 pour indiquer que la fonction a échoué
    // A la lecture du return, la fonction s'arrête immédiatement.
}


Je n'ai pas grand chose à rajouter là. J'ouvre le fichier dico.txt en lecture seule ("r") et je vérifie si j'ai réussi en testant si dico vaut NULL ou pas. Si dico vaut NULL, le fichier n'a pas pu être ouvert (fichier introuvable ou occupé par un autre programme). Dans ce cas j'affiche une erreur et je fais un return 0.

Pourquoi un return là ? En fait, l'instruction return commande l'arrêt de la fonction. Si le dico n'a pas pu être ouvert, la fonction s'arrête là et l'ordinateur n'ira pas lire plus loin. On retourne 0 pour indiquer au main que la fonction a échoué.

Dans la suite de la fonction, on suppose donc que le fichier a été bien ouvert.


Code : C
1
2
3
4
5
6
7
8
// On compte le nombre de mots dans le fichier (il suffit de compter les
// entrées \n
do
{
    caractereLu = fgetc(dico);
    if (caractereLu == '\n')
        nombreMots++;
} while(caractereLu != EOF);


Là, on parcourt tout le fichier à coups de fgetc (caractère par caractère). On compte le nombre d'\n (entrées) qu'on détecte. A chaque fois qu'on tombe sur un \n, on incrémente la variable nombreMots.
Grâce à ce bout de code, on obtient dans nombreMots le nombre de mots dans le fichier (rappelez-vous que le fichier contient un mot par ligne).


Code : C
1
numMotChoisi = nombreAleatoire(nombreMots); // On pioche un mot au hasard


Là, je fais appel à une fonction de mon crû qui va génèrer un nombre aléatoire entre 1 et nombreMots (le paramètre qu'on envoie à la fonction).
C'est une fonction toute simple que j'ai placée aussi dans dico.c (je vous la détaillerai tout à l'heure).

Bref, elle renvoie un numéro au hasard qu'on stocke dans numMotChoisi.


Code : C
1
2
3
4
5
6
7
8
// On recommence à lire le fichier depuis le début. On s'arrête lorsqu'on est arrivés au bon mot
rewind(dico);
while (numMotChoisi > 0)
{
    caractereLu = fgetc(dico);
    if (caractereLu == '\n')
        numMotChoisi--;
}


Maintenant qu'on a le numéro du mot qu'on veut piocher, on repart au début grâce à un appel à rewind()
On parcourt là encore le fichier caractère par caractère en comptant les \n. Cette fois, on décrémente la variable numMotChoisi. Si par exemple on a choisi le mot numéro 5, à chaque entrée le variable va être décrémentée de 1.
Elle va donc valoir 5, puis 4, 3, 2, 1... et 0.
Lorsque la variable vaut 0, on sort du while (la condition du while numMotChoisi > 0 n'est plus remplie).

Ce bout de code, que vous devez impérativement comprendre, vous montre donc comment on parcourt un fichier pour se placer à la position voulue. Ce n'est pas bien compliqué, mais ce n'est pas non plus "super évident". Assurez-vous donc de bien comprendre ce que je fais là.


Maintenant, on devrait avoir un curseur positionné juste devant le mot secret qu'on a choisi de piocher.
On va le stocker dans motPioche (le paramètre que la fonction reçoit) grâce à un simple fgets qui va lire le mot :

Code : C
1
2
3
4
5
6
/* Le curseur du fichier est positionné au bon endroit.
On n'a plus qu'à faire un fgets qui lira la ligne */
fgets(motPioche, 100, dico);

// On vire l'\n à la fin
motPioche[strlen(motPioche) - 1] = '\0';


On demande au fgets de ne pas lire plus de 100 caractères (c'est la taille du tableau motPioche, qu'on a défini dans le main).
N'oubliez pas que fgets lit toute une ligne, y compris l'\n.
Comme on ne veut pas garder cet \n dans le mot final, on le supprime en le remplaçant par un \0. Cela aura pour effet de couper la chaîne juste avant l'\n.


Et... voilà qui est fait :)
On a écrit le mot secret dans la mémoire à l'adresse de motPioche.

On n'a plus qu'à fermer le fichier et à retourner 1 pour que la fonction s'arrête et pour dire que tout s'est bien passé :

Code : C
1
2
3
4
fclose(dico);

    return 1; // Tout s'est bien passé, on retourne 1
}




Yahou :D
C'est tout pour la fonction piocherMot ^^



La fonction nombreAleatoire



C'est la fonction dont j'avais promis de vous parler tout à l'heure. On tire un nombre au hasard et on le renvoie :

Code : C
1
2
3
4
5
long nombreAleatoire(long nombreMax)
{
    srand(time(NULL));
    return (rand() % nombreMax);
}


La première ligne initialise le générateur de nombres aléatoires, comme on a appris à le faire dans le premier TP "Plus ou Moins".
La seconde ligne prend un nombre au hasard entre 0 et nombreMax et renvoie ça (j'ai tout mis dans le return comme un gros bourrin que je suis :p )


Le fichier dico.h



Il s'agit juste des prototypes des fonctions.
Vous remarquerez qu'il y a la "protection" #ifndef que je vous avais demandé d'inclure dans tous vos fichiers .h (revoyez le chapitre sur le préprocesseur au besoin ;) )

Code : C
1
2
3
4
5
6
7
8
#ifndef DEF_DICO
#define DEF_DICO


int piocherMot(char *motPioche);
long nombreAleatoire(long nombreMax);

#endif



Le fichier dico.c



Voici le fichier dico.c en entier :

Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
/*
Jeu du pendu
Par M@teo21, pour le Site du Zér0
<lien url="www.siteduzero.com">www.siteduzero.com</lien>

dico.c
------

Ces fonctions piochent au hasard un mot dans un fichier dictionnaire
pour le jeu du pendu
*/

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>

#include "dico.h"


int piocherMot(char *motPioche)
{
    FILE* dico = NULL; // Le pointeur de fichier qui va contenir notre fichier
    long nombreMots = 0, numMotChoisi = 0;
    int caractereLu = 0;

    dico = fopen("dico.txt", "r"); // On ouvre le dictionnaire en lecture seule

    // On vérifie si on a réussi à ouvrir le dictionnaire
    if (dico == NULL) // Si on n'a PAS réussi à ouvrir le fichier
    {
        printf("\nImpossible de charger le dictionnaire de mots");
        return 0; // On retourne 0 pour indiquer que la fonction a échoué
        // A la lecture du return, la fonction s'arrête immédiatement.
    }

    // On compte le nombre de mots dans le fichier (il suffit de compter les
    // entrées \n). Pensez à laisser une Entrée après le dernier mot du dico !
    do
    {
        caractereLu = fgetc(dico);
        if (caractereLu == '\n')
            nombreMots++;
    } while(caractereLu != EOF);

    numMotChoisi = nombreAleatoire(nombreMots); // On pioche un mot au hasard

    // On recommence à lire le fichier depuis le début. On s'arrête lorsqu'on est arrivés au bon mot
    rewind(dico);
    while (numMotChoisi > 0)
    {
        caractereLu = fgetc(dico);
        if (caractereLu == '\n')
            numMotChoisi--;
    }

    /* Le curseur du fichier est positionné au bon endroit.
    On n'a plus qu'à faire un fgets qui lira la ligne */
    fgets(motPioche, 100, dico);

    // On vire l'\n à la fin
    motPioche[strlen(motPioche) - 1] = '\0';

    fclose(dico);

    return 1; // Tout s'est bien passé, on retourne 1
}


long nombreAleatoire(long nombreMax)
{
    srand(time(NULL));
    return (rand() % nombreMax);
}




Il va falloir modifier le main !



Maintenant que le fichier dico.c est prêt, on retourne dans le main() pour l'adapter un petit peu aux quelques changements qu'on vient de faire.

Déjà, on commence par inclure dico.h si on veut pouvoir faire appel aux fonctions de dico.c ;)
Ensuite, on va inclure string.h en plus là aussi car on va devoir faire un strlen :

Code : C
1
2
#include <string.h>
#include "dico.h"



Pour commencer, les définitions de variables vont un peu changer. Déjà, on n'initialise plus la chaine motSecret, on crée juste un grand tableau de char (100 cases)...

Quant au tableau lettreTrouvee... sa taille dépendra de la longueur du mot secret qu'on aura pioché. Comme on ne connaît pas encore cette taille, on crée un simple pointeur. Tout à l'heure, on fera un malloc et on fera pointer ce pointeur vers la zone mémoire qu'on aura allouée.
Ceci est un exemple parfait où l'allocation dynamique est indispensable : on ne connaît pas la taille du tableau avant la compilation, on est donc obligés de créer un pointeur et de faire un malloc.
Je ne dois pas oublier de libérer la mémoire ensuite quand je n'en ai plus besoin, d'où la présence d'un free() à la fin du main().

On va aussi avoir besoin d'une variable tailleMot qui va stocker... la taille du mot ^^ En effet, si vous regardez le main() tel qu'il était dans la première partie, on supposait que le mot faisait 6 caractères partout (et c'était vrai car MARRON fait 6 lettres). Mais maintenant que le mot peut changer de taille, il va falloir être capable de s'adapter à tous les mots ;)

Voici donc les définitions de variables du main en version finale :

Code : C
1
2
3
4
5
6
7
8
int main(int argc, char* argv[])
{
    char lettre = 0; // Stocke la lettre proposée par l'utilisateur (retour du scanf)
    char motSecret[100] = {0}; // Ce sera le mot à trouver
    int *lettreTrouvee = NULL; // Un tableau de booléens. Chaque case correspond à une lettre du mot secret. 0 = lettre non trouvée, 1 = lettre trouvée
    long coupsRestants = 10; // Compteur de coups restants (0 = mort)
    long i = 0; // Une petite variable pour parcourir les tableaux
    long tailleMot = 0;


C'est principalement le début du main() qui va changer, donc analysons-le de plus près :

Code : C
1
2
if (!piocherMot(motSecret))
    exit(0);


On fait d'abord appel à piocherMot directement dans le if.
piocherMot va placer dans motSecret le mot qu'elle aura pioché.

De plus, piocherMot va renvoyer un booléen pour nous dire si la fonction a réussi ou échoué. Le rôle du if est d'analyser ce booléen. Si ça n'a PAS marché (le "!" permet d'exprimer la négation), alors on arrête tout (exit(0)).


Code : C
1
tailleMot = strlen(motSecret);


On stocke la taille du motSecret dans tailleMot comme je vous l'ai dit tout à l'heure.



Code : C
1
2
3
lettreTrouvee = malloc(tailleMot * sizeof(int)); // On alloue dynamiquement le tableau lettreTrouvee (dont on ne connaissait pas la taille au départ)
if (lettreTrouvee == NULL)
    exit(0);


Maintenant on doit allouer la mémoire pour le tableau lettreTrouvee comme je vous l'ai dit. On lui donne la taille du mot (tailleMot).
On vérifie ensuite si le pointeur n'est pas NULL. Si c'est le cas, c'est que l'allocation a échoué. Dans ce cas, on arrête immédiatement le programme (on fait appel à exit()).

Si les lignes suivantes sont lues, c'est que tout s'est bien passé.




Voilà, grosso modo ce sont tous les préparatifs qu'il vous fallait faire ici.
J'ai dû ensuite modifier le reste du fichier main.c pour remplacer tous les nombres 6 (l'ancienne longueur de MARRON qu'on avait fixée) par la variable tailleMot :)
Par exemple :

Code : C
1
2
for (i = 0 ; i < tailleMot ; i++)
    lettreTrouvee[i] = 0;


Ce code met toutes les cases du tableau lettreTrouvee à 0 (en s'arrêtant lorsqu'on a parcouru tailleMot cases).

J'ai dû aussi modifier le prototype de la fonction gagne pour ajouter la variable tailleMot. Sans cela, la fonction n'aurait pas su quand arrêter sa boucle.


Voici le fichier main.c final en entier :

Code : C
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/*
Jeu du pendu
Par M@teo21, pour le Site du Zér0
<lien url="www.siteduzero.com">www.siteduzero.com</lien>

main.c
------

Fonctions principales de gestion du jeu
*/

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

#include "dico.h"

int gagne(int lettreTrouvee[], long tailleMot);
int rechercheLettre(char lettre, char motSecret[], int lettreTrouvee[]);
char lireCaractere();

int main(int argc, char* argv[])
{
    char lettre = 0; // Stocke la lettre proposée par l'utilisateur (retour du scanf)
    char motSecret[100] = {0}; // Ce sera le mot à trouver
    int *lettreTrouvee = NULL; // Un tableau de booléens. Chaque case correspond à une lettre du mot secret. 0 = lettre non trouvée, 1 = lettre trouvée
    long coupsRestants = 10; // Compteur de coups restants (0 = mort)
    long i = 0; // Une petite variable pour parcourir les tableaux
    long tailleMot = 0;

    printf("Bienvenue dans le Pendu !\n\n");

    if (!piocherMot(motSecret))
        exit(0);

    tailleMot = strlen(motSecret);

    lettreTrouvee = malloc(tailleMot * sizeof(int)); // On alloue dynamiquement le tableau lettreTrouvee (dont on ne connaissait pas la taille au départ)
    if (lettreTrouvee == NULL)
        exit(0);

    for (i = 0 ; i < tailleMot ; i++)
        lettreTrouvee[i] = 0;

    // On continue à jouer tant qu'il reste au moins un coup à jouer ou qu'on
    // n'a pas gagné
    while (coupsRestants > 0 && !gagne(lettreTrouvee, tailleMot))
    {
        printf("\n\nIl vous reste %ld coups a jouer", coupsRestants);
        printf("\nQuel est le mot secret ? ");

        /* On affiche le mot secret en masquant les lettres non trouvées
        Exemple : *A**ON */
        for (i = 0 ; i < tailleMot ; i++)
        {
            if (lettreTrouvee[i]) // Si on a trouvé la lettre n°i
                printf("%c", motSecret[i]); // On l'affiche
            else
                printf("*"); // Sinon, on affiche une étoile pour les lettres non trouvées
        }

        printf("\nProposez une lettre : ");
        lettre = lireCaractere();

        // Si ce n'était PAS la bonne lettre
        if (!rechercheLettre(lettre, motSecret, lettreTrouvee))
        {
            coupsRestants--; // On enlève un coup au joueur
        }
    }


    if (gagne(lettreTrouvee, tailleMot))
        printf("\n\nGagne ! Le mot secret etait bien : %s", motSecret);
    else
        printf("\n\nPerdu ! Le mot secret etait : %s", motSecret);

    free(lettreTrouvee); // On libère la mémoire allouée manuellement (par malloc)

        return 0;
}


char lireCaractere()
{
    char caractere = 0;

    caractere = getchar(); // On lit le premier caractère
    caractere = toupper(caractere); // On met la lettre en majuscule si elle ne l'est pas déjà

    // On lit les autres caractères mémorisés un à un jusqu'à l'\n
    while (getchar() != '\n') ;

    return caractere; // On retourne le premier caractère qu'on a lu
}


int gagne(int lettreTrouvee[], long tailleMot)
{
    long i = 0;
    int joueurGagne = 1;

    for (i = 0 ; i < tailleMot ; i++)
    {
        if (lettreTrouvee[i] == 0)
            joueurGagne = 0;
    }

    return joueurGagne;
}

int rechercheLettre(char lettre, char motSecret[], int lettreTrouvee[])
{
    long i = 0;
    int bonneLettre = 0;

    // On parcourt motSecret pour vérifier si la lettre proposée y est
    for (i = 0 ; motSecret[i] != '\0' ; i++)
    {
        if (lettre == motSecret[i]) // Si la lettre y est
        {
            bonneLettre = 1; // On mémorise que c'était une bonne lettre
            lettreTrouvee[i] = 1; // On met à 1 le case du tableau de booléens correspondant à la lettre actuelle
        }
    }

    return bonneLettre;
}

Idées d'amélioration

Télécharger le projet



Pour commencer, je vous invite à télécharger le projet de Pendu que j'ai fait :



Si vous êtes sous Linux ou Mac, supprimez le fichier dico.txt et recréez-vous en un. Les fichiers sont enregistrés de manière différente sous Windows, donc si vous utilisez le mien vous risquez d'avoir des bugs.
N'oubliez pas qu'il faut qu'il y ait une Entrée après chaque mot du dictionnaire. Pensez en particulier à mettre une Entrée après le dernier mot de la liste.


Ca va vous permettre de tester par vous-mêmes le fonctionnement du projet, de faire éventuellement des améliorations par-dessus etc etc. Bien entendu, le mieux serait que vous ayez déjà réussi le pendu par vous-mêmes et que vous n'ayez même pas besoin de voir mon projet pour voir comment j'ai fait mais... je suis réaliste, je sais que ce TP a dû être assez délicat pour bon nombre d'entre vous ;)

Vous trouverez dans ce zip les fichiers .c et .h ainsi que le fichier .cbp du projet. C'est un projet fait sous Code::Blocks oui :)
Si vous utilisez un autre IDE, pas de panique. Vous créez un nouveau projet console et vous y ajoutez manuellement les .c et .h que vous trouverez dans le zip.

Vous trouverez aussi l'exécutable (.exe Windows) ainsi qu'un petit dictionnaire (dico.txt) pour commencer ;)


Améliorez le pendu !



Mine de rien, le pendu est déjà assez évolué comme ça ^^
On a un jeu qui lit un fichier de dictionnaire et qui prend à chaque fois un mot au hasard.

Voici quand même quelques idées d'amélioration qui me passent par la tête :




Prenez bien le temps de comprendre ce jeu de Pendu et améliorez-le jusqu'au maximum. Il faut que vous soyez capables de refaire ce petit jeu de Pendu les yeux fermés !

Allez courage :)

Pfiou !

Ca n'a pas été facile, mais on y arrive toujours n'est-ce pas ? Si vous voulez vraiment progresser en C, il vous faut pratiquer. Inventez des jeux si c'est ce qui vous amuse, inventez des petits utilitaires (éditeur de texte en console) si c'est votre domaine à vous... Faites ce que vous voulez, mais programmez ! Entraînez-vous !


Une fois que vous serez bien à l'aise avec les programmes en console...
...

... Oh mais... qu'entends-je ? Qu'ouïe-je ?
Mais oui ! C'est bien l'appel de la librairie SDL ! :D

J'entrevois... une foule de possibilités qui s'offre à vous maintenant !
Des programmes en fenêtre, en plein écran, de la 2D, du son, le contrôle du clavier, de la souris, du joystick...


Attends-moi SDL, j'arriiiiiiiiiiiiive !!!!!
Chapitre précédent Sommaire Chapitre suivant
Retour en haut Retour en haut


Créé : le 29/07/2005 à 00:29:36
Modifié : le 13/09/2008 à 16:59:49
Avancement : 100%
Licence : Copie non autorisée

75 commentaires

Changer de design | En savoir plus | Plan du site | Politique d'accessibilité | Règles | RSS tutoriels | RSS news
Édité par Simple IT SARL : Nous contacter | Notre blog | Revue de presse | Publicité

Y'a plus rien à lire, faut remonter maintenant !