Partage
  • Partager sur Facebook
  • Partager sur Twitter

Problème partie 1 du TP : réalisation d'un pendu

Sujet résolu
    7 juin 2021 à 22:35:54

    Bonjour à tous !

    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

    • Partager sur Facebook
    • Partager sur Twitter
      7 juin 2021 à 23:24:16

      LucasLethuillier a écrit:

      en tout cas je n'ai aucun message d'erreur 

      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 !

      • Partager sur Facebook
      • Partager sur Twitter
        8 juin 2021 à 4:43:40

        } 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?
        • Partager sur Facebook
        • Partager sur Twitter

        Le Tout est souvent plus grand que la somme de ses parties.

          8 juin 2021 à 9:09:09

          rouloude a écrit:

          J'ai un warning : ligne 17 

          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 :euh: 


          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

          • Partager sur Facebook
          • Partager sur Twitter
            8 juin 2021 à 9:52:24

            Bonjour,

            on joue tant que on a des vies (compteurVies != 0) et qu'on n'a pas trouvé ( strcmp(...)!=0 ),

            est la même chose que 

            on arrête de jouer si on n'a plus de vies (compteurVies==0) ou qu'on a trouvé ( strcmp(...)==0 ).

            NON (A OU  B) == (NON A) ET (NON B)

            • Partager sur Facebook
            • Partager sur Twitter
              8 juin 2021 à 10:28:46

              White Crow a écrit:

              Bonjour,

              on joue tant que on a des vies (compteurVies != 0) et qu'on n'a pas trouvé ( strcmp(...)!=0 ),

              est la même chose que 

              on arrête de jouer si on n'a plus de vies (compteurVies==0) ou qu'on a trouvé ( strcmp(...)==0 ).

              NON (A OU  B) == (NON A) ET (NON B)


              Super ! J'ai bien compris comme ça :) merci
              • Partager sur Facebook
              • Partager sur Twitter
                8 juin 2021 à 15:09:35

                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 ...

                • Partager sur Facebook
                • Partager sur Twitter

                Le Tout est souvent plus grand que la somme de ses parties.

                  8 juin 2021 à 15:28:30

                  PierrotLeFou a écrit:

                  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;
                  }

                  -
                  Edité par rouloude 8 juin 2021 à 15:33:26

                  • Partager sur Facebook
                  • Partager sur Twitter
                    8 juin 2021 à 16:23:06

                    bah tient ça me rappelle un vieux truc ^_^

                    #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 :p

                    • Partager sur Facebook
                    • Partager sur Twitter
                      8 juin 2021 à 17:12:48

                      PierrotLeFou a écrit:

                      En Pascal, il y a (avait?) des boucles do ... until

                      Au fait ! Ce n'était pas plutôt repeat until ? 'répéter' 'tant que'

                      Ce qui ferait alors :

                      #include <stdio.h>
                      
                      #define repeat do
                      #define until(x) while(!(x))
                      
                      int main(void)
                      {
                          char c;
                      
                          repeat
                          {
                              c = getchar();
                          }
                          until(c=='n' || c=='N');
                      
                          return 0;
                      }




                      • Partager sur Facebook
                      • Partager sur Twitter
                        8 juin 2021 à 23:15:09

                        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 !

                        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 o_O  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

                        • Partager sur Facebook
                        • Partager sur Twitter
                          9 juin 2021 à 1:06:14

                          @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 ...
                          • Partager sur Facebook
                          • Partager sur Twitter

                          Le Tout est souvent plus grand que la somme de ses parties.

                            9 juin 2021 à 13:44:37

                             bonjour, 

                            White Crow a écrit:

                            bah tient ça me rappelle un vieux truc ^_^

                            #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 :p

                            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
                                    returner 0 _
                            }

                            Non mais vraiment:D




                            -
                            Edité par TheSmiley 9 juin 2021 à 13:46:56

                            • Partager sur Facebook
                            • Partager sur Twitter
                              9 juin 2021 à 17:06:58

                              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

                              • Partager sur Facebook
                              • Partager sur Twitter
                                9 juin 2021 à 17:14:26

                                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
                                • Partager sur Facebook
                                • Partager sur Twitter
                                  9 juin 2021 à 17:18:44

                                  AntoineBarbier12 a écrit:

                                  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

                                  • Partager sur Facebook
                                  • Partager sur Twitter

                                  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.
                                  • Editeur
                                  • Markdown