Partage
  • Partager sur Facebook
  • Partager sur Twitter

Jeu du pendu

    11 août 2019 à 15:09:53

    Bonjour à tous,

    Depuis quelques temps je m'entraine sur le jeu du pendu en essayant de l'améliorer.

    J'ai beau chercher mais je suis confronté depuis quelques temps à un problème. Soit le jeu bug dès que je le lance, soit tout marche bien et au bout d'un certain temps, alors que j'ai trouvé le mot mystère, la partie ne se termine pas en annonçant que j'ai gagné. Le mot est révélé mais le programme continue de me faire entrer des lettres et enlève une vie à chaque entrée bien que le mot sois découvert.

    Je vous joins le code. J'ai totalement conscience de ne pas avoir codé de la plus belle des façons et qu'il sera difficile de détecter mes erreurs donc si vous avez des conseils pour mieux organiser/structurer ce code et le rendre plus "pro" c'est avec grand plaisir

    N'oubliez pas que je débute et je ne demande qu'à m'améliorer. Tout commentaire allant dans ce sens serait super !

    #include <stdio.h>
    #include <stdlib.h>
    #include <ctype.h>
    #include <string.h>
    #include <time.h>
    #include <math.h>
    #include <windows.h>
    #include <conio.h>
    void regles(FILE * fichier);
    void sousMenuDico(FILE * fichier);
    void nouvellePartie(FILE * fichier);
    void readDico(FILE * fichier);
    
    
    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'au \n (pour les effacer)
        while (getchar() != '\n') ;
        return caractere; // On retourne le premier caractère qu'on a lu
    }
    //Fonction qui vérifie si la lettre a déjà été découverte. Si oui on enlève une vie, si non on ajoute cette lettre à mot et on incrémente l'indice associé du tableau booléen tab.
    void trouverLettre(char lettre, char motSecret[], char mot[], int tab[], int * vie)
    {
        int i;
        int compteur = 0;                       //Verifie si la lettre est dans le mot secret
        int compteur1 = 0;                      //Verifie si la lettre a déjà été découverte
        for(i = 0; i < strlen(motSecret); i++)
        {
            if(mot[i] == lettre)
            {
                compteur1++;
            }
            if(motSecret[i] == lettre)
            {
                tab[i] = 1;
                mot[i] = motSecret[i];
                compteur++;
            }
    
        }
        if(compteur == 0)
        {
            *vie-=1;
        }
        if(compteur1 >= 1)
        {
            *vie-=1;
        }
    }
    
    //Fonction qui vérifie si on a gagné c'est à dire si toutes les cases de tab sont à 1
    int gagne(int tab[], int size)
    {
        int i;
        int compteur = 0;
        for(i = 0; i < size; i++)
        {
            compteur += tab[i];             //On additionne les cases du tableau booléen tab[]
        }
        if(compteur == size)                   //Si tab[] est remplie de 1 alors on a gagné
        {
            printf("Vous avez gagne !! \n");
            return 1;
        }
        return 0;
    }
    
    //Retourne le nombre de ligne dans le dico
    int comptageLigneDico(FILE * fichier)
    {
    
        int nbreLignes = 0;
        char caractereActuel;
    
            do
            {
                caractereActuel = fgetc(fichier);
                if(caractereActuel == '\n')
                {
                    nbreLignes++;
                }
            }while(caractereActuel != EOF);
    
    
        nbreLignes++; //On rajoute la derniere ligne
        return nbreLignes;
    }
    
    //Compte le nombre de caractères pour une ligne donnée dans le dico
    int comptageCaractereLigne(FILE * fichier, int nbrLigne)
    {
        char caractereActuel;
        int nbrCaractere = 0;
        int ligne = 1;
    
            if(nbrLigne == 1)
            {
                rewind(fichier);
                do
                {
                    caractereActuel = fgetc(fichier);
                    nbrCaractere++;                         //Prend en compte le retour a la ligne. Il faut donc retrancher 1
                }while(caractereActuel != '\n');
                return (nbrCaractere - 1);
            }
            else if(nbrLigne == comptageLigneDico(fichier))
            {
                rewind(fichier);
                do
                {
                    caractereActuel = fgetc(fichier);
                    if(caractereActuel == '\n')
                    {
                        ligne++;
                    }
                }while(ligne != nbrLigne);
                do
                {
                    caractereActuel = fgetc(fichier);
                    nbrCaractere++;                //DE meme on retranche 1 pour avoir le nombre exacte de caracteres
                }while(caractereActuel != EOF);
                return (nbrCaractere - 1);
            }
            else
            {
                rewind(fichier);
                do
                {
                    caractereActuel = fgetc(fichier);
                    if(caractereActuel == '\n')
                    {
                        ligne++;
                    }
                }while(ligne != nbrLigne);
                do
                {
                    caractereActuel = fgetc(fichier);
                    nbrCaractere++;
                }while(caractereActuel != '\n');
                return (nbrCaractere - 1);
            }
    
    
    
    }
    
    //Initialise Tab et Mot
    void remplissageTabMot(char mot[], int tab[], int size)
    {
        int i;
        for(i = 0; i < size; i++)
        {
            tab[i] = 0;
            mot[i] = '*';
        }
    }
    
    //Remplit motSecret
    void remplissageMotSecret(char motSecret[], FILE * fichier, int nbrLigne, int size)
    {
        char caractereActuel;
        int ligne = 1;
        int k = 0;
    
            if(nbrLigne == 1)       //Cas où on doit remplir avec le premier mot du dico
            {
                rewind(fichier);
                do
                {
                    caractereActuel = fgetc(fichier);
                    k++;                         //Prend en compte le retour a la ligne. Il faut donc retrancher 1
                    motSecret[k - 1] = caractereActuel;
                }while(caractereActuel != '\n');
            }
    
            else if(nbrLigne == comptageLigneDico(fichier))     //Cas où on doit remplir avec le dernier mot du dico
            {
                rewind(fichier);
                do
                {
                    caractereActuel = fgetc(fichier);
                    if(caractereActuel == '\n')
                    {
                        ligne++;
                    }
                }while(ligne != nbrLigne);
                do
                {
                    caractereActuel = fgetc(fichier);
                    k++;
                    motSecret[k - 1] = caractereActuel;
                }while(caractereActuel != EOF);
            }
    
            else                                        //Cas ou on doit remplir avec un mot quelconque autre que le premier du dico ou le dernier
            {
                rewind(fichier);
                do
                {
                    caractereActuel = fgetc(fichier);
                    if(caractereActuel == '\n')
                    {
                        ligne++;
                    }
                }while(ligne != nbrLigne);
                do
                {
                    caractereActuel = fgetc(fichier);
                    k++;
                    motSecret[k - 1] = caractereActuel;
                }while(caractereActuel != '\n');
            }
    
    
    
    }
    
    //Fonctions d'allocation de mémoire pour les différents tableaux
    char * allocationMot(int nbrCaracteres)
    {
        return malloc(nbrCaracteres * sizeof(char));
    }
    int * allocationTab(int nbrCaracteres)
    {
        return malloc(nbrCaracteres * sizeof(int));
    }
    char * allocationMotSecret(int nbrCaracteres)
    {
        return malloc(nbrCaracteres * sizeof(char));
    }
    
    
    //Menu principal du jeu
    void menu_Principal(FILE * fichier)
    {
        int choix = 0;
        int validation = 200;
        char touche;
        int nbrChoixMenuePrincipal = 4;
        int etatBoucle = 1;     //On quittle la boucle si 0
    
        printf("===========================\n");
        printf("==Bienvenue dans le pendu==\n");
        printf("===========================\n\n");
        printf("-> Regles\n");
        printf("  Dictionnaire\n");
        printf("  Nouvelle partie\n");
        printf("  Quitter");
    
        while(etatBoucle)
        {
            if(kbhit())
            {
                touche = getch();
                switch(touche)
                {
                case 'z':   //On monte
                    choix = fabs((choix + nbrChoixMenuePrincipal - 1) % nbrChoixMenuePrincipal);
                    break;
                case's':      //On descend
                    choix = fabs((choix + 1) % nbrChoixMenuePrincipal);
                    break;
                case'a':       //On valide
                    validation = choix;
                    break;
                }
                switch(validation)
                {
                case 0:
                    system("cls");
                    regles(fichier);
                    break;
                case 1:
                    system("cls");
                    sousMenuDico(fichier);
                    break;
                case 2:
                    system("cls");
                    nouvellePartie(fichier);
                    break;
                case 3:
                    system("cls");
                    etatBoucle = 0;
                    printf("A tres bientot !\n");
                    fclose(fichier);
                    exit(0);
                    break;
                }
    
                switch(choix)
                {
                case 0:
                    system("cls");
                    printf("===========================\n");
                    printf("==Bienvenue dans le pendu==\n");
                    printf("===========================\n\n");
                    printf("-> Regles\n");
                    printf("  Dictionnaire\n");
                    printf("  Nouvelle partie\n");
                    printf("  Quitter\n");
                    break;
                case 1:
                    system("cls");
                    printf("===========================\n");
                    printf("==Bienvenue dans le pendu==\n");
                    printf("===========================\n\n");
                    printf("  Regles\n");
                    printf("->  Dictionnaire\n");
                    printf("  Nouvelle partie\n");
                    printf("  Quitter\n");
                    break;
                case 2:
                    system("cls");
                    printf("===========================\n");
                    printf("==Bienvenue dans le pendu==\n");
                    printf("===========================\n\n");
                    printf("  Regles\n");
                    printf("  Dictionnaire\n");
                    printf("->  Nouvelle partie\n");
                    printf("  Quitter\n");
                    break;
                case 3:
                    system("cls");
                    printf("===========================\n");
                    printf("==Bienvenue dans le pendu==\n");
                    printf("===========================\n\n");
                    printf("  Regles\n");
                    printf("  Dictionnaire\n");
                    printf("  Nouvelle partie\n");
                    printf("->  Quitter\n");
                    break;
                }
    
            }
        }
    
    
    }
    
    //Fonction affichant les règles
    void regles(FILE * fichier)
    {
        int etat = 1;
        char touche;
    
            system("cls");
            printf("Le but de ce jeu est de trouver le mot mystere.\n Pour cela vous disposez de 10 vies.\n Vous perdez la partie si vous perdez toutes vos vie\n\n");
            printf("-> Retour");
            while(etat)
        {
            if(kbhit())
            {
                touche = getch();
                switch(touche)
                {
                case'a':
                    system("cls");
                    etat = 0;
                    menu_Principal(fichier);
                    break;
                }
            }
        }
    
    }
    
    //Sous menu permettant au joueur de regarder le Dico sous réserve qu'il possède le mot de passe ou de le modifier
    void sousMenuDico(FILE * fichier)
    {
        int choix = 0;
        int validation;
        int etatBoucle = 1;
        int nbrChoixMenu = 3;
        char touche;
    
        printf("-> Voir le dictionnaire\n");
        printf("  Modifier le dictionnaire\n");
        printf("  Retour\n");
    
        while(etatBoucle)
        {
            if(kbhit())
            {
                touche = getch();
                switch(touche)
                {
                case'z':
                    choix = fabs((choix + nbrChoixMenu - 1) % nbrChoixMenu);
                    break;
                case's':
                    choix = fabs((choix + 1) % nbrChoixMenu);
                    break;
                case'a':
                    validation = choix;
                    break;
                }
    
                switch(choix)
                {
                case 0:
                    system("cls");
                    printf("-> Voir le dictionnaire\n");
                    printf("  Modifier le dictionnaire\n");
                    printf("  Retour\n");
                    break;
                case 1:
                    system("cls");
                    printf(" Voir le dictionnaire\n");
                    printf("->  Modifier le dictionnaire\n");
                    printf("  Retour\n");
                    break;
                case 2:
                    system("cls");
                    printf(" Voir le dictionnaire\n");
                    printf("  Modifier le dictionnaire\n");
                    printf("-> Retour\n");
                }
                switch(validation)
                {
                case 0:
                    system("cls");
                    readDico(fichier);
                    break;
                case 1:
                    system("cls");
                    //modifDico(); fonction pas encore codée
                    break;
                case 2:
                    system("cls");
                    menu_Principal(fichier);
                    break;
                }
            }
        }
    }
    
    //Fonction permettant de lire le dictionnaire
    void readDico(FILE * fichier)
    {
        int etat = 1;
        char password[] = "dictionnaire";
        char motDePasse[13];
        char touche;
        char caractereActuel;
        printf("Entrez le mot de passe \n");
        gets(motDePasse);
        printf("\n");
        if(strcmp(password,motDePasse) == 0)
        {
            do
            {
                caractereActuel = fgetc(fichier);
                printf("%c",caractereActuel);
            }while(caractereActuel != EOF);
    
    
        printf("\n\n");
        printf("-> Retour");
        while(etat == 1)
        {
            if(kbhit())
        {
            touche = getch();
            switch(touche)
            {
            case 'a':
                system("cls");
                fclose(fichier);
                etat = 0;
                sousMenuDico(fichier);
                break;
            }
        }
    
        }
    
        }
        else
        {
            printf("mot de passe incorrect ! \n");
            sousMenuDico(fichier);
        }
    }
    //Fonction qui débute une partie du pendu
    void nouvellePartie(FILE * fichier)
    {
            int rejouer = 0;            //Booléen qui vaut 1 si on veut rejouer, 0 si on ne veut pas
        do
        {
        //Création du dictionnaire
        int aleatoire = (rand()%(comptageLigneDico(fichier)) + 1);
    
    //Création des tableaux dynamique
        char * motSecret = allocationMotSecret(comptageCaractereLigne(fichier,aleatoire));
    
        char * mot = allocationMot(comptageCaractereLigne(fichier,aleatoire));
    
        int * tab = allocationTab(comptageCaractereLigne(fichier,aleatoire));
    
        remplissageTabMot(mot,tab,comptageCaractereLigne(fichier,aleatoire));
    
        remplissageMotSecret(motSecret,fichier,aleatoire,comptageCaractereLigne(fichier,aleatoire));
    
    
        char lettre;
        int vie = 10;
        int i;
        int compteurGagne = 0;
        do
        {
        fflush(stdin);                  //On vide le buffer sinon dès que l'on recommence une partie la première lettre entré lu sera ce qui était en mémoire dans le buffer
        printf("Il vous reste %d coups a jouer\n", vie);
        printf("proposez une lettre : ");
        lettre = lireCaractere();       //Fonction qui lit un caractère en vidant le buffer
        trouverLettre(lettre,motSecret,mot,tab,&vie);
        printf("Le mot secret est : ");
        for(i = 0; i < comptageCaractereLigne(fichier,aleatoire); i++)    //On affiche le mot dévoilé par le joueur
        {
            printf("%c", mot[i]);
        }
        printf("\n");
    
        printf("\n");
    
        if(gagne(tab,comptageCaractereLigne(fichier,aleatoire)))          //On vérifie si on a gagné
        {
            compteurGagne = 1;
        }
        if(vie == 0)
        {
            printf("Vous avez perdu !! \n\n");
        }
    
        }while((compteurGagne != 1) && (vie > 0));      //On saisie des lettres tant qu'on a de la vie et que l'on n'a pas gagné
        printf("Voulez-vous rejouer ?\n");      //On change la valeur de rejouer. Selon cette valeur la boucle continue ou non
        printf("1.oui\n");
        printf("2.non\n");
        scanf("%d",&rejouer);
        //On libère la mémoire pour pouvoir rejouer
        free(tab);
        free(mot);
        free(motSecret);
        system("cls");
    
        }while(rejouer == 1);
        menu_Principal(fichier);
    
    }
    
    int main()
    {
        printf("Prouduit par CrashTest\n");
        Sleep(2000);
        system("cls");
        srand(time(NULL));
        FILE * fichier = fopen("Dico.txt","r");
        if(fichier != NULL)
        {
                menu_Principal(fichier);
        //fclose(fichier);
        }
        else
        {
            printf("Erreur ouverture du fichier main");
        }
        return 0;
    }
    


    -
    Edité par VitamineD 11 août 2019 à 16:54:41

    • Partager sur Facebook
    • Partager sur Twitter
      11 août 2019 à 15:48:38

      Quand on fait des programmes de plus de 500 lignes de code, le minimum serait de lire est corriger les warnings !

      Puis ensuite tu peux utiliser un débogueur.

      J'ai tenté de le compiler, j'ai une erreur et plusieurs warnings. (fonctions non déclarées ou incorrectement appelées).

      • Partager sur Facebook
      • Partager sur Twitter
        11 août 2019 à 16:46:13

        Effectivement je viens de régler le problème la compilation marche maintenant de mon côté et il n'y a plus de warnings !

        J'ai également oublié de préciser que les touches pour se déplacer dans le menu sont : 'z' pour monter et 's' pour descendre ainsi que 'a' pour valider.

        Il faut également que vous créez un fichier "Dico.txt" dans lequel vous pouvez mettre tous les mots que vous voulez pour le jeu.

        Le mot de passe pour accéder au dictionnaire est : dictionnaire

        Je viens de mettre à jour le code sur mon premier post.

        Je pense avoir trouvé l'origine du bug de mon programme. J'ai mis un retour à la ligne dans mon fichier Dico.txt et le jeu qui bugait lorsque le programme choisissait le dernier mot du dictionnaire ne bug plus.

        J'utilise bien le fait qu'il y ait un saut à la ligne pour récupérer un mot dans le dico mais ce qui est étrange c'est que je n'utilise pas cette technique pour le dernier mot du dico! Je lis entre le saut de ligne avant le dernier mot et le caractère de fin EOF. Je ne vois donc pas pourquoi le saut à la ligne à la toute fin du dico est nécessaire...

        Edit : le jeu continue quand même à crash de temps en temps... notamment quand je veux recommencer une nouvelle partie après avoir trouvé mon mot mystère

        -
        Edité par VitamineD 11 août 2019 à 17:16:17

        • Partager sur Facebook
        • Partager sur Twitter
          12 août 2019 à 16:53:34

          Bonjour,

          Utilise un debugger comme te l'as suggéré rouloude. Tu lances ton programme après une compilation en mode "débug" (c'est assez simple avec un IDE), normalement à la moindre erreur de segmentation (SIGSEGV) tu devrais être au courant, ton IDE t'affiches la ligne posant problème. Sinon, tu places des breakpoints puis tu lis les variables dans une fenêtre au moment du breakpoint (watches ou quelque chose comme ça). :)

          • Partager sur Facebook
          • Partager sur Twitter

          Mon site web de jeux SDL2 entre autres : https://www.ant01.fr

            12 août 2019 à 19:46:49

            Excellent outil le debugger merci !

            Est ce qu'une personne pourrait m'indiquer ce que signifie les lignes au niveau de motSecret et de mot ? Je vois en effet le mot tel quel mais il y a, on dirait, un caractère hexadécimal devant. De même à la ligne de tab et lettre. A t'il une signification particulière ? Serait-ce l'adresse à laquelle est situé le tableau ? De même les caractères situés à la fin indiquent-ils la fin du tableau ou ont une tout autre signification ?

            Une dernière question. Si j'ai un problème d'allocation de mémoire(tableau trop grand ou qui utilise de la mémoire là où il n'est pas censé en prendre), est ce que le debuggeur peut m'indiquer où se situe ce problème ?

            Merci

            Watches

            -
            Edité par VitamineD 12 août 2019 à 19:57:41

            • Partager sur Facebook
            • Partager sur Twitter

            Jeu du 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