Je viens de terminer la première partie du TP qui consiste à réaliser un "Jeu du pendu". Le code que je propose est fonctionnel (en tout cas je n'ai aucun message d'erreur et j'ai testé le jeu avec différents mots). Cependant, j'ai remarqué au travers des différents exercices du début du cours qu'il m'arrivait d'avoir un code qui me semble fonctionnel mais qui contient en fait de petites erreurs. Etant donné que je débute en programmation, je serai intéressé d'avoir l'avis de personnes plus expérimentées sur ma version du code, notamment pour me dire si j'ai fait des erreurs que je n'aurais pas vu ou utilisé une méthode qui serait "à éviter" car elle pourrait causer des problèmes dans le futur.
Merci d'avance :)
PS : dans le do...while de ma fonction main, j'utilise un && (ET) mais j'ai d'abord voulu utiliser un || (OU). Je ne comprends toujours pas réellement pourquoi le OU ne fonctionne pas :/
Mon fichier headers.h :
#ifndef DEF_HEADERS
#define DEF_HEADERS
// Protoypes de mes fonctions
void afficherRegles();
char lireCaractere();
void revelationLettre(char mot1[], char lettreAReveler, char mot2[], char *pointeurMot1);
int rejouer();
#endif
Mon fichier main.c :
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "headers.h"
#define NOMBRE_VIES_INIT 10
int main()
{
char lettreProposee = 0 ;
char motSecret[] = "MARRON"; // Le mot secret est fixe pour le moment
char motSecretCrypte[] = "******";
char* pointeurMotSecret = motSecret;
char* pointeurMotSecretCrypte = motSecretCrypte;
int compteurVies = NOMBRE_VIES_INIT;
int i = 0;
int retourMenu = 0;
do
{
afficherRegles();
do
{
printf("Il vous reste %d vies !\n", compteurVies);
printf("Quel est le mot secret ? %s", pointeurMotSecretCrypte);
printf("\nProposez une lettre : ");
lettreProposee = lireCaractere();
if (strchr(motSecret, lettreProposee) != NULL) // Si "lettreProposée" par le joueur est trouvée dans "motSecret"
{
revelationLettre(motSecret, lettreProposee, motSecretCrypte, pointeurMotSecret);
}
else // Autrement, la lettre proposée n'est pas trouvée dans "motSecret" et on perd donc une vie
{
compteurVies --;
}
printf("\n");
} while (compteurVies != 0 && strcmp(motSecretCrypte, motSecret) != 0); // POURQUOI PAS UN || dans ma condition ???
if (compteurVies == 0)
{
printf("Vous avez perdu !\n");
}
else if (strcmp(motSecretCrypte, motSecret) == 0)
{
printf("Bravo ! Vous avez trouve le mot secret qui etait : %s !\n", pointeurMotSecretCrypte);
}
retourMenu = rejouer();
} while (retourMenu == 1);
return 0;
}
void afficherRegles()
{
printf("\n=== JEU DU PENDU ===\n");
printf("\nBIENVENU DANS LE JEU DU PENDU!\n");
printf("\nBUT DU JEU:\n");
printf("\n\tDecouvrir le mot secret\n");
printf("\nREGLES DU JEU:\n");
printf("\n\t1) Entrez une lettre a la fois\n");
printf("\t2) Les accents ne sont pas pris en compte\n");
printf("\t3) Vous disposez de 10 vies pour decouvrir le mot secret\n");
printf("\nBONNE CHANCE !!\n\n");
}
// PERMET DE RELANCER UNE PARTIE
int rejouer()
{
int rejouer = 0;
printf("\n--- FIN DE LA PARTIE ---\n");
printf("\nTapez 1 pour revenir au menu principal\n");
printf("Tapez 2 pour quitter le jeu\n");
printf("\nVotre choix: ");
scanf("%d", &rejouer);
return rejouer;
}
// PERMET DE LIRE LA LETTRE ENTREE DANS LA CONSOLE PAR LE JOUEUR
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à
while (getchar() != '\n') ; // On lit les autres caractères mémorisés un à un jusqu'au \n (pour les effacer)
return caractere; // On retourne le premier caractère qu'on a lu
}
// PERMET DE REVELER LA LETTRE PROPOSEE PAR LE JOUEUR SI ELLE EST JUSTE
void revelationLettre(char mot1[], char lettreAReveler, char mot2[], char *pointeurMot1)
{
int i = 0;
for (i = 0; i < 6; i++)
{
if (mot1[i] == lettreAReveler) // Si la lettre correspond à la ième lettre du mot secret
{
mot2[i] = pointeurMot1[i]; // On copie le ième caractère pointé par "pointeurMot1" à la ième position de "mot2"
}
}
}
- Edité par LucasLethuillier 9 juin 2021 à 14:29:46
J'ai un warning : ligne 17 variable i non utilisé !
As-tu testé ton jeu ? Car si je refais une deuxième partie (sans stopper le programme) le mot à rechercher s'affiche en clair et il suffit de rentrer une seul lettre pour gagner !
} while (compteurVies != 0 && strcmp(motSecretCrypte, motSecret) != 0); // POURQUOI PAS UN || dans ma condition Regardons la condition inverse: if (compteurVies == 0 || strcmp(motSecretCrypte, motSecret) == 0); Je sort si le compteur est nul OU si la comparaison est vraie. Ce n'est pas ce que tu veux?
Le Tout est souvent plus grand que la somme de ses parties.
Merci pour ta réactivité ! Effectivement, j'avais listé les différentes variables dont j'aurais besoin quand j'ai commencé à écrire le code. J'ai placé la variable i dans ma fonction "revelationLettre" et j'ai oublié de la supprimer dans ma fonction main...
rouloude a écrit:
[...] si je refais une deuxième partie (sans stopper le programme) le mot à rechercher s'affiche en clair et il suffit de rentrer une seul lettre pour gagner !
J'ai testé le jeu trop rapidement ! J'ai vu que le programme se relançait lorsque je voulais rejouer mais je n'ai pas vérifié la partie suivante .. En changeant de mot je n'ai pas pu le remarquer puisque je stoppais le programme à chaque fois. Pardonnes moi ma précipitation
PierrotLeFou a écrit:
Regardons la condition inverse: if (compteurVies == 0 || strcmp(motSecretCrypte, motSecret) == 0); Je sort si le compteur est nul OU si la comparaison est vraie. Ce n'est pas ce que tu veux?
Merci pour ta réponse ! Si et je suis d'accord, c'est ce que je veux. Il me semble bien que c'est l'inverse de ce que tu as proposé dans le if. C'est pour cela que je ne comprends pas pourquoi écrire :
} while (compteurVies != 0 || strcmp(motSecretCrypte, motSecret) != 0);
ne fonctionne pas.
Selon moi :
} while (compteurVies != 0 && strcmp(motSecretCrypte, motSecret) != 0);
peut se traduire "je répète la boucle tant que le compteur de vies n'est pas arrivé à 0 ET tant que les chaines motSecretCrypte et motSecret ne sont pas les même". Or, ne devrait-il pas suffire que l'une des deux conditions soit satisfaite pour que l'on sorte de la boucle (l'une OU l'autre du coup) ?
Mais je fais peut être une grosse erreur de compréhension !
- Edité par LucasLethuillier 8 juin 2021 à 23:15:58
En Pascal, il y a (avait?) des boucles do ... until On boucle "jusqu'à" cette condition et non pas tant que cette condition. Ça aurait fait ton bonheur ...
Le Tout est souvent plus grand que la somme de ses parties.
En Pascal, il y a (avait?) des boucles do ... until On boucle "jusqu'à" cette condition et non pas tant que cette condition. Ça aurait fait ton bonheur ...
On pourrait le faire avec une macro :
#include <stdio.h>
#define until(x) while(!(x))
int main(void)
{
char c;
do
{
c = getchar();
}
until (c=='n' || c=='N');
return 0;
}
[...] si je refais une deuxième partie (sans stopper le programme) le mot à rechercher s'affiche en clair et il suffit de rentrer une seul lettre pour gagner !
Du coup j'ai fait une modification pour réinitialiser compteurVies (10 vies quand on lance une deuxième partie) et motSecretCrypte ("******" est bien affiché quand on lance une deuxième partie). J'ai ajouté ce code dans mon main (juste après avoir appelé ma fonction afficherRegles et juste avant ma deuxième boucle do...while) :
// Si on revient au menu après une première partie
if (retourMenu == 1)
{
// On réinitialise le "compteurVies"
compteurVies = NOMBRE_VIES_INIT;
// On remplace le ième caractère de "motSecretCrypte" par une "*" pour le re-crypter
for (i = 0; i < 6; i++)
{
motSecretCrypte[i] = '*';
}
}
Malheureusement, lorsque je rejoue une deuxième partie, la première lettre proposée par le joueur est toujours considérée comme fausse même si elle fait partie du mot recherché.. Ensuite la partie continue normalement ! Je ne comprends pas trop pourquoi il y a un problème au premier essai seulement Surtout que si j'affiche motSecret, motSecretCrypte et leurs pointeurs respectifs via des printf, ils semblent bien réinitialisés ! (voir affichage console ci-dessous)
--- FIN DE LA PARTIE ---
Tapez 1 pour revenir au menu principal
Tapez 2 pour quitter le jeu
Votre choix: 1
=== JEU DU PENDU ===
BIENVENU DANS LE JEU DU PENDU!
BUT DU JEU:
Decouvrir le mot secret
REGLES DU JEU:
1) Entrez une lettre a la fois
2) Les accents ne sont pas pris en compte
3) Vous disposez de 10 vies pour decouvrir le mot secret
BONNE CHANCE !!
MARRON
MARRON
******
******
Il vous reste 10 vies !
Quel est le mot secret ? ******
Proposez une lettre : a
MARRON
MARRON
******
******
Il vous reste 9 vies !
Quel est le mot secret ? ******
Proposez une lettre :
- Edité par LucasLethuillier 9 juin 2021 à 12:05:23
@rouloude: Tu as raison, c'était repeat ... until J'avais utilisé un truc semblable pour convertir du Pascal en C avec GNU sed J'avais un paquet de while(!(condition)) à reconvertir ...
Le Tout est souvent plus grand que la somme de ses parties.
#define LOCAL static
#define PROC extern
#define TYPE typedef
#define STRUCT TYPE struct
#define UNION TYPE union
#define REG register
#define IF if(
#define THEN ){
#define ELSE } else {
#define ELIF } else if (
#define FI ;}
#define BEGIN {
#define END }
#define SWITCH switch(
#define IN ){
#define ENDSW }
#define FOR for(
#define WHILE while(
#define DO ){
#define OD ;}
#define REP do{
#define PER }while(
#define DONE );
#define LOOP for(;;){
#define POOL }
#define SKIP ;
#define DIV /
#define REM %
#define NEQ ^
#define ANDF &&
#define ORF ||
#define TRUE (-1)
#define FALSE 0
pour ne pas faire du C en C
et aprés on dit que le C est dificile :
#include <stdio.h>
#define si if
#define DEBUT {
#define FIN }
#define sinon else
#define _ ;
#define dire printf
#define EGAL_A =
#define nombre int
#define returner return
#define EST_EGAL_A ==
#define et &&
#define ou ||
nombre main() {
nombre f EGAL_A 6 _
si (f EST_EGAL_A 6) DEBUT _
dire(" hello world") _
FIN
sinon DEBUT _
dire("bonjour tout le monde") _
FIN
Grâce à un post sur un autre forum, j'ai trouvé la dernière erreur dans mon code. Il fallait faire un "while (getchar() != '\n');" dans ma fonction "rejouer" pour effacer le <return> (= \n) enregistré en mémoire lorsqu'on utilise la touche entrée pour valider le choix de rejouer une partie.
J'ai également simplifié ma fonction "revelationLettre" qui ne nécessite absolument pas l'utilisation de pointeurs.
Maintenant, le programme fonctionne correctement mais je pense que cette méthode pour révéler les lettres n'est pas aussi bonne que celle proposée dans le cours.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "headers.h"
#define NOMBRE_VIES_INIT 10
int main()
{
char lettreProposee = 0 ;
char motSecret[] = "MARRON"; // Le mot secret est fixe pour le moment
char motSecretCrypte[] = "******";
int retourMenu = 0;
int i = 0;
int compteurVies = NOMBRE_VIES_INIT;
do
{
afficherMenu();
// Si on revient au menu après une première partie
if (retourMenu == 1)
{
// On réinitialise le "compteurVies"
compteurVies = NOMBRE_VIES_INIT;
// On remplace le ième caractère de "motSecretCrypte" par une "*" pour le re-crypter
for (i = 0; i < 6; i++)
{
motSecretCrypte[i] = '*';
}
}
do
{
printf("Il vous reste %d vies !\n", compteurVies);
printf("Quel est le mot secret ? %s", motSecretCrypte);
printf("\nProposez une lettre : ");
lettreProposee = lireCaractere();
if (strchr(motSecret, lettreProposee) != NULL) // Si "lettreProposée" par le joueur est trouvée dans "motSecret"
{
revelationLettre(6, motSecret, lettreProposee, motSecretCrypte);
}
else // Autrement, la lettre proposée n'est pas trouvée dans "motSecret" et on perd donc une vie
{
compteurVies --;
}
printf("\n");
} while (compteurVies != 0 && strcmp(motSecretCrypte, motSecret) != 0);
if (compteurVies == 0)
{
printf("Vous avez perdu !\n");
}
else if (strcmp(motSecretCrypte, motSecret) == 0)
{
printf("Bravo ! Vous avez trouve le mot secret qui etait : %s !\n", motSecretCrypte);
}
retourMenu = rejouer();
} while (retourMenu == 1);
return 0;
}
void afficherMenu()
{
printf("\n=== JEU DU PENDU ===\n");
printf("\nBIENVENU DANS LE JEU DU PENDU!\n");
printf("\nBUT DU JEU:\n");
printf("\n\tDecouvrir le mot secret\n");
printf("\nREGLES DU JEU:\n");
printf("\n\t1) Entrez une lettre a la fois\n");
printf("\t2) Les accents ne sont pas pris en compte\n");
printf("\t3) Vous disposez de 10 vies pour decouvrir le mot secret\n");
printf("\nBONNE CHANCE !!\n\n");
}
// PERMET DE RELANCER UNE PARTIE
int rejouer()
{
int rejouer = 0;
printf("\n--- FIN DE LA PARTIE ---\n");
printf("\nTapez 1 pour revenir au menu principal\n");
printf("Tapez 2 pour quitter le jeu\n");
printf("\nVotre choix: ");
scanf("%d", &rejouer);
while (getchar() != '\n') ;
return rejouer;
}
// PERMET DE LIRE LA LETTRE ENTREE PAR LE JOUEUR DANS LA CONSOLE
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à
while (getchar() != '\n') ; // On lit les autres caractères mémorisés un à un jusqu'au \n (pour les effacer)
return caractere; // On retourne le premier caractère qu'on a lu
}
// PERMET DE REVELER LA LETTRE PROPOSEE PAR LE JOUEUR SI ELLE EST JUSTE
void revelationLettre(int tailleMots, char mot1[], char lettreAReveler, char mot2[])
{
int i = 0;
for (i = 0; i < tailleMots; i++)
{
if (mot1[i] == lettreAReveler) // Si la lettre correspond à la ième lettre du mot secret
{
mot2[i] = mot1[i]; // On copie le ième caractère à la ième position de "mot2"
}
}
}
- Edité par LucasLethuillier 9 juin 2021 à 17:15:54
essaie de créer plus de fonction pour décomposer ton code et que il n'y a pas trop de code dans le main
Oui, c'est une remarque que j'ai eu sur l'autre forum également. Je le ferai de mon coté, mais je voulais juste poster la solution au "gros" problème de mon précédent code qui n'était pas fonctionnel. Merci !
- Edité par LucasLethuillier 9 juin 2021 à 17:19:37
Problème partie 1 du TP : réalisation d'un pendu
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
Le Tout est souvent plus grand que la somme de ses parties.
Le Tout est souvent plus grand que la somme de ses parties.
Le Tout est souvent plus grand que la somme de ses parties.