Partage
  • Partager sur Facebook
  • Partager sur Twitter

Fonction qui tourne à l'infini

    28 avril 2024 à 13:11:08

    Bonjour à tous, je suis bloqué depuis quelque temps sur mon programme, ma fonction "choixDifficulte" ne fonctionne plus correctement. Le programme se met à bloquer lors de l'éxecution de celle-ci, comme si le scanf ne récupérait rien alors que je crois qu'il récupère bien les données. Tout était ok depuis que je l'avais codé. Je n'ai aucune piste, alors j'espère que quelqu'un connait le problème !

    J'envoie le programme en entier :



    // importation des bibliothèques
    
    #include <stdlib.h>
    #include <stdio.h>
    #include <time.h>
    #include <unistd.h>
    
    // définition des couleurs
    
    #define RESET "\033[0m"
    #define ROUGE "\033[31m"
    #define VERT "\033[32m"
    #define JAUNE "\033[33m"
    #define BLEU "\033[34m"
    #define VIOLET "\033[35m"
    #define BLEUCYAN "\033[36m" 
    #define couleur(couleur) printf(couleur)
    
    typedef struct {
        int valeur; //La case est négative si est une mine, et prend la valeur du nombre de mines autour sinon
        int caseDevoilee; //-1 si la case n'est pas dévoilée, 0 si c'est un drapeau, 1 si elle est dévoilée
    } Case;
    
    typedef struct { //Structure pour associer un nom à un score
        int score;
        char nom[10];
    } Records;
    
    //Fonction pour trier les meilleurs scores dans l'odre croissant 
    
    void triDesScores(Records *leaderboard, int nombreScores) {
        Records scoreTemp;
        for (int j=0; j<nombreScores-1; j++) {
            for (int i=j+1; i<nombreScores; i++) {
                if (leaderboard[j].score > leaderboard[i].score) {
                    scoreTemp = leaderboard[j];
                    leaderboard[j] = leaderboard[i];
                    leaderboard[i] = scoreTemp;
                }
            }
        }
    }
    
    //Fonctions effacer une ligne du fichier "scores.txt"
    
    void effacerLigne(FILE *scores) {
        int caractere = fgetc(scores);
    
        while (caractere != '\n' || caractere != EOF) {
            fputc(' ', scores);
        }
    }
    
    //Fonction pour écrire une ligne des scores du fichier "scores.txt"
    
    void ecrireMeilleursScores(FILE *scores, Records *leaderboard, int nombreScores) {
        for (int i=0; i<nombreScores; i++) {
            fprintf(scores, "%s:%d ", leaderboard[i].nom, leaderboard[i].score);
        }
    }
    
    //Fonction pour choisir la ligne voulue du fichier "scores.txt"
    
    void choixLigne(int ligne, FILE *scores) {
        int caractere = fgetc(scores), compteur = 0;
    
        for (int i=0; i<ligne; i++) {
            while (caractere != '\n' || caractere != EOF) {
                caractere = fgetc(scores);
                compteur++;
            }
            printf("Ligne %d sur %d", compteur, ligne);
        }
    }
    
    void actualisationFichierScores(int tailleGrille, int nombreMines, Records *leaderboard, int nombreScores) {
        FILE *scores = fopen("/Users/mathieurouet/Documents/Écoles/CY TECH/Projets/Démineur_V1/scores.txt", "r+");
    
        if (scores == NULL) {
            printf("L'ouverture du fichier 'scores' a échoué\n\n");
            return;
        }
    
        if (tailleGrille == 9 && nombreMines == 10) {
            rewind(scores);
            effacerLigne(scores);
            ecrireMeilleursScores(scores, leaderboard, nombreScores);
        } else if (tailleGrille == 16 && nombreMines == 40) {
            choixLigne(1, scores);
            effacerLigne(scores);
            ecrireMeilleursScores(scores, leaderboard, nombreScores);
        } else {
    
        }
        fclose(scores);
    }
    
    //Fonction pour récupérer le nom d'un joueur et le score d'un joueur
    
    void getNomEtScore(Records *leaderboard, FILE *scores, int numeroJoueur) {
        int caractere, compteurLettre = 0;
    
        caractere = fgetc(scores);
        while (caractere != ':') {
            leaderboard[numeroJoueur].nom[compteurLettre] = caractere;
            caractere = fgetc(scores);
            compteurLettre++;
        }
        leaderboard[numeroJoueur].nom[compteurLettre] = '\0';
    
        fscanf(scores, "%d", &leaderboard[numeroJoueur].score);
    }
    
    /*Fonction pour lire les meilleurs scores et en informer le joueur
    Normes du fichier scores :
        Les scores sont écrit par niveau croissants (Scores du niveau 1 dans l'ordre croissant, puis scores du niveau 2,...)
        Les 5 meilleurs scores sont écrits à la suite, avec un nom associé pour les 2 premiers niveau, avec ':' pour différencier les noms des scores, avec un espace entre chaque scores, et on revient à la ligne à la fin
        Pour le niveau 3 (grille personnalisée), on utilise le même procédé, en sautant de ligne pour chaque nombre de mines +1, tout en terminant par '.' pour signifier la fin d'une section de taille de grille
    */
    
    int lectureFichierScores(int tailleGrille, int nombreMines, Records *leaderboard) {
        int compteurScores = 0, caractere, ligne = 0;
        FILE *scores = fopen("/Users/mathieurouet/Documents/Écoles/CY TECH/Projets/Démineur_V1/scores.txt", "r");
    
        if (scores == NULL) {
            printf("L'ouverture du fichier 'scores' a échoué\n\n");
            return compteurScores;
        }
    
        //Calcule de la ligne se trouvant les scores de la grille et du nombre de mines sélectionnés
    
        for (int i=3; i<tailleGrille; i++) {
            for (int j=1; j<=i-1; j++) {
                ligne++;
            }
        }
        ligne += nombreMines;
    
        choixLigne(ligne, scores);
        caractere = fgetc(scores);
        if (caractere != ' ') { //Vérification que la ligne des meilleurs scores n'est pas vide
            fseek(scores, -1, SEEK_CUR); //Si la ligne n'est pas vide, on revient un caractère en arrière
            while (caractere != '\n' && caractere != EOF) {
    
                //On récupère le nom est le score des meilleurs joueurs
    
                getNomEtScore(leaderboard, scores, compteurScores);
                printf("%s : %d\n", leaderboard[compteurScores].nom, leaderboard[compteurScores].score);
    
                caractere = fgetc(scores);
    
                compteurScores++;
            }
        }
        fclose(scores);
        return compteurScores;
    }
    
    //Fonction pour afficher le tableau des scores
    
    void afficherLeaderboard(Records *leaderboard, int compteur) {
        triDesScores(leaderboard, compteur);
        printf("Les meilleurs scores sont :\n");
        for (int i=0; i<compteur; i++) {
            printf("N°%d) %s - %d secondes\n", i+1, leaderboard[i].nom, leaderboard[i].score);
        }
        puts("");
    }
    
    //Fonction récuperant le choix de difficulté fait par l'utilisateur
    
    int choixDifficulte(int *nombreMines) {
        int difficulte;
    
        printf("Jouons au démineur !\n\nChoisissez votre niveau de difficulté (1, 2, ou 3 pour une partie personnalisée) : ");
        scanf("%d", &difficulte);
    
        //Vérification de la bonne saisie de la difficulté
    
        while (difficulte != 1 && difficulte != 2 && difficulte != 3) {
            printf("\nErreur, la diffuculté ne peut être comprise qu'entre 1, 2 et 3, nouveau choix : ");
            while (getchar() != '\n'); //On vide le buffer (problème de boucle infinie sinon)
            scanf("%d", &difficulte);
        }
    
        if (difficulte == 1) {
            *nombreMines = 10;
            return 9;
        } else if (difficulte == 2) {
            *nombreMines = 40;
            return 16;
        } else { //Partie personnalisée
            int tailleGrille;
    
            //Choix de la taille de la grille
    
            printf("\nChoix de la difficulté personnalisée !\nChoisissez une taille de grille entre 3 et 40 : ");
            scanf("%d", &tailleGrille);
    
            while (tailleGrille < 3 || tailleGrille > 40) {
                printf("\nErreur, la taille de la grille doit être comprise entre 3 et 40, nouveau choix : ");
                while (getchar() != '\n'); //On vide le buffer (problème de boucle infinie sinon)
                scanf("%d", &tailleGrille);
            }
    
            //Choix de nombre de mine
    
            printf("Choisissez le nombre de mines à mettre dans votre grille de taille %d (minimum 1, maximum %d) : ", tailleGrille, tailleGrille*tailleGrille - 1);
            scanf("%d", nombreMines);
            while (*nombreMines < 1 || *nombreMines > tailleGrille*tailleGrille - 1) {
                printf("\nErreur, le nombre de mines doit être compris entre 1 et %d, nouveau choix : ", tailleGrille*tailleGrille - 1);
                while (getchar() != '\n'); //On vide le buffer (problème de boucle infinie sinon)
                scanf("%d", nombreMines);
            }
            return tailleGrille;
        }
    }
    
    //Fonction initialisant toutes les variables des cases à l'état initial (valeur = 0 et caseDevoilee = -1)
    
    void initialisationGrille(int tailleGrille, Case **grille) {
        for (int i=0; i<tailleGrille; i++) {
            for (int j=0; j<tailleGrille; j++) {
                grille[i][j].valeur = 0;
                grille[i][j].caseDevoilee = -1;
            }
        }
    }
    
    /* Fonction placant les mines aléatoirement sur la grille et actualisant en conséquence la valeur des cases autour de celle-ci
    
    Principe :
        Génère un nombre x et un nombre y aléatoire, compris entre 0 et la taille d'une colonne de la grille
        Ce nombre donne les coordonnées de la mine à placer.
        Une boucle while permet de regénérer des coordonnées aléatoires si une mine se trouve déjà à cette position
        Une fois la case validée, la valeur de celle-ci prend -1, indiquant qu'une mine s'y trouve
        De plus, on ajoute +1 à la valeur des cases voisines, indiquant qu'une mine se trouve à proximité directe
    */
    
    void placementMines(int tailleGrille, Case **grille, int nombreMines) {
        int x, y;
        srand(time(NULL));
    
        //Procédure de placement aléatoire des mines
    
        for (int i=0; i<nombreMines; i++) {
            do {
                x = rand() % tailleGrille;
                y = rand() % tailleGrille;
            } while (grille[x][y].valeur < 0);
            grille[x][y].valeur = -1;
    
            //Actualisation des cases autour de la nouvelle mine
             
            for (int k=-1; k<2; k++) {
                for (int j=-1; j<2; j++) {
                    if (x-k < 0 || y-j < 0 || x-k >= tailleGrille || y-j >= tailleGrille) continue; //Si la case séléctionnée n'existe pas, on passe
                    if (grille[x-k][y-j].valeur == -1) continue; //Si la case séléctionnée est une mine, on passe
                    grille[x-k][y-j].valeur ++;
                }
            }
    
        }
    }
    
    /* Fonction affichant la grille, longue car j'ai voulu afficher des couleurs
    
    On pouvait aussi faire :
    
                    case 1:
                        switch (grille[i][j].valeur) {
                            case -1:
                                printf("[X]");
                                break;
                            default:
                                if (grille[i][j].valeur == 0) printf("[/]");
                                else printf("[%d]", grille[i][j].valeur);
                                break;
                        }
                    ...
    */
    
    void afficherGrille(int tailleGrille, Case **grille) {
        puts("");
        printf("     ");
        for (int i = 0; i<tailleGrille; i++) {
            if (i >= 10) printf(" %d", i);
            else printf(" %d ", i);
        }
        puts("");
        printf("     ");
        for (int i = 0; i<tailleGrille; i++) {
            printf(" | ");
        }
        puts("");
        printf("     ");
        for (int i = 0; i<tailleGrille; i++) {
            printf(" V ");
        }
        puts("");
    
        for (int i=0; i<tailleGrille; i++) {
            if (i >= 10) printf("%d-> ", i);
            else printf("%d -> ", i);
    
            for (int j=0; j<tailleGrille; j++) {
                switch (grille[i][j].caseDevoilee) {
                    case 1:
                        switch (grille[i][j].valeur) {
                            case -1:
                                printf("[");
                                couleur(VIOLET);
                                printf("X");
                                couleur(RESET);
                                printf("]");
                            break;
                            case 1:
                                printf("[");
                                couleur(BLEUCYAN);
                                printf("1");
                                couleur(RESET);
                                printf("]");
                                break;
                            case 2:
                                printf("[");
                                couleur(BLEU);
                                printf("2");
                                couleur(RESET);
                                printf("]");
                                break;
                            case 3:
                                printf("[");
                                couleur(VERT);
                                printf("3");
                                couleur(RESET);
                                printf("]");
                                break;
                            case 4:
                                printf("[");
                                couleur(JAUNE);
                                printf("4");
                                couleur(RESET);
                                printf("]");
                                break;
                            case 5:
                                printf("[");
                                couleur(ROUGE);
                                printf("5");
                                couleur(RESET);
                                printf("]");
                                break;
                            case 6:
                                printf("[");
                                couleur(VIOLET);
                                printf("6");
                                couleur(RESET);
                                printf("]");
                                break;
                            case 7:
                                printf("[");
                                couleur(VIOLET);
                                printf("7");
                                couleur(RESET);
                                printf("]");
                                break;
                            case 8:
                                printf("[");
                                couleur(VIOLET);
                                printf("9");
                                couleur(RESET);
                                printf("]");
                                break;
                        default:
                            printf("[/]");
                            break;
                        }
                        break;
                    case 0:
                        printf("[P]");
                        break;
                    default:
                        printf("[ ]");
                        break;
                }
            }
            if (i >= 10) printf(" <-%d", i);
            else printf(" <- %d", i);
            puts(""); //Saut de ligne
        }
        puts("");
        printf("     ");
        for (int i = 0; i<tailleGrille; i++) {
            printf(" ^ ");
        }
        puts("");
        printf("     ");
        for (int i = 0; i<tailleGrille; i++) {
            printf(" | ");
        }
        puts("");
        printf("     ");
        for (int i = 0; i<tailleGrille; i++) {
            if (i >= 10) printf(" %d", i);
            else printf(" %d ", i);
        }
        puts("");
    }
    
    //Fonction récupérant les choix de l'utilisateur pendant la partie
    
    int choixUtilisateur(int tailleGrille, Case **grille, int *x, int *y) {
        int choix;
    
        printf("Action choisie (1 dévoiler une case, 2 placer un drapeau) : ");
        scanf("%d", &choix);
    
        //Vérification de la bonne saisie du choix
    
        while (choix != 1 && choix != 2) {
            printf("\nErreur, le choix ne peut être comprise qu'entre 1 et 2, nouvelle saisie : ");
            while (getchar() != '\n'); //On vide le buffer (problème de boucle infinie sinon)
            scanf("%d", &choix);
        }
    
        printf("\nCoordonnées de la case choisie : ");
        scanf("%d %d", x, y);
    
        //Vérification de la bonne saisie des coordonnées (coordonnées existantes et case pas encore dévoilée)
    
        while ((*x < 0 && *x >= tailleGrille) || (*y < 0 && *y >= tailleGrille) || grille[*x][*y].caseDevoilee == 1) {
            if ((*x < 0 && *x >= tailleGrille) || (*y < 0 && *y >= tailleGrille)) printf("\nErreur, les coordonnées ne peuvent comprises qu'entre 0 et %d, nouvelle saisie : ", tailleGrille - 1);
            else printf("\nErreur, la case choisie est déjà dévoilée, nouvelle saisie : ");
            while (getchar() != '\n'); //On vide le buffer (problème de boucle infinie sinon)
            scanf("%d %d", x, y);
        }
    
        return choix;
    }
    
    /*Fonction actualisant les cases de la grille en fonction de l'action précédente de l'utilisateur, de plus, elle indique si on tombe sur une mine
    
    2 cas :
        1) La case est à côté d'une mine ou une mine, on révèle simplement la case, et si c'est une mine, la fonction renvoie 1, indiquant la fin du jeu
        2) La case n'est à côté d'aucune mine, dans ce cas, on doit révéler toutes les cases autour jusqu'à trouver une case avec au moins une mine à côté
    
    Principe de l'algorithme du deuxième cas :
        On dévoile toutes les cases autour de la case initiale
        Si une case voisine ne contient pas non plus de mine autour, on répète l'algorithme en rappelant la fonction
        L'algorithme s'arrête seulement une fois qu'il ne reste plus de case avec aucune mine autour à révéler
    */
    
    int actualisationGrille(int tailleGrille, Case **grille, int choix, int x, int y) {
        if (choix == 2) {
            if (grille[x][y].caseDevoilee == 0) grille[x][y].caseDevoilee = -1; //Si la case est déjà un drapeau, on le suprime
            else grille[x][y].caseDevoilee = 0;
        }
    
        else {
            grille[x][y].caseDevoilee = 1;
            if (grille[x][y].valeur != 0) { //Cas où la case dévoilée est à côté d'une mine
                if (grille[x][y].valeur < 0) return 1; //Si la case est une mine, on renvoie 1
            }
    
            else {
                for (int i=-1; i<2; i++) {
                    for (int j=-1; j<2; j++) {
                        if (x-i < 0 || y-j < 0 || x-i >= tailleGrille || y-j >= tailleGrille || (x == x-i && y == y-j)) continue; //Si la case séléctionnée n'existe pas ou est la case intiale, on passe
                        if (grille[x-i][y-j].valeur == 0 && grille[x-i][y-j].caseDevoilee == -1) actualisationGrille(tailleGrille, grille, 1, x-i, y-j); //Si la case voisine n'a pas de mine autour, alors on répète l'algorithme
                        grille[x-i][y-j].caseDevoilee = 1;
                    }
                }
            }
        }
    
        return 0;
    }
    
    //Fonction esthétique qui montre le placements des mines à la fin de partie
    
    void revelationMines(int tailleGrille, Case **grille) {
        for (int i=0; i<tailleGrille; i++) {
            for (int j=0; j<tailleGrille; j++) {
                if (grille[i][j].valeur == -1) grille[i][j].caseDevoilee = 1;
            }
        }
    }
    
    //Fonction vérifiant que le joueur n'a pas encore dévoilée toutes les cases non-mine
    
    int victoireJoueur(int tailleGrille, Case **grille) {
        for (int i=0; i<tailleGrille; i++) {
            for (int j=0; j<tailleGrille; j++) {
                if ((grille[i][j].caseDevoilee == -1 || grille[i][j].caseDevoilee == 0) && grille[i][j].valeur >= 0) return 0;
            }
        }
        return 1;
    }
    
    //Fonction demandant à l'utilisateur s'il souhaite rejouer
    
    int rejouer() {
        char choix;
    
        printf("Voulez-vous rejouer ? (o pour oui, n pour non) ");
        scanf(" %c", &choix);
    
        while (choix != 'o' && choix != 'n') {
            printf("\nErreur, le choix ne peut être que o (oui) ou n (non), nouvelle saisie : ");
            while (getchar() != '\n'); //On vide le buffer (problème de boucle infinie sinon)
            scanf("%c", &choix);
        }
    
        //La fonction renvoie le choix (1 si on rejoue, 0 sinon)
    
        if (choix == 'o') return 1;
        return 0;
    }
    
    //Fonction de jeu
    
    int jeu(int tailleGrille, Case **grille, int nombreMines) {
        int partieEnCours = 1;
        int choix, x, y;
    
        //Initialisation de la grille et placement des mines
    
        initialisationGrille(tailleGrille, grille);
        placementMines(tailleGrille, grille, nombreMines);
    
        //Initialisation du chronomètre
    
        time_t debut = time(NULL), fin;
    
        //Boucle permettant de jouer jusqu'à l'arrêt du jeu
    
        while (partieEnCours) {
            afficherGrille(tailleGrille, grille);
            choix = choixUtilisateur(tailleGrille, grille, &x, &y);
            if (actualisationGrille(tailleGrille, grille, choix, x, y) || victoireJoueur(tailleGrille, grille)) partieEnCours = 0;
        }
    
        //Message de fin en fonction du résultat de la partie, et contrôle si le joueur veut rejouer
    
        fin = time(NULL);
        revelationMines(tailleGrille, grille);
        afficherGrille(tailleGrille, grille);
    
        switch (victoireJoueur(tailleGrille, grille)) {
            case 1:
                printf("\n\nFélicitations ! Vous avez fini cette grille en %.0lf secondes !\n\n", difftime(fin, debut));
                if (rejouer()) return 1;
                return 0;
            default:
                printf("\n\nVous avez perdu... Temps écoulé : %.0lf secondes\n\n", difftime(fin, debut));
                if (rejouer()) return 1;
                return 0;
        }
    }
    
    void affichageScores() {
        FILE *scores = fopen("scores.txt", "r+");
    
        fclose(scores);
    }
    
    int main() {
        int tailleGrille, nombreMines, partieEnCours = 1;
        Records leaderboard[5];
    
        while (partieEnCours) {
    
            //Choix de la difficulté
    
            tailleGrille = choixDifficulte(&nombreMines);
    
            int nombreScores = lectureFichierScores(tailleGrille, nombreMines, leaderboard);
            afficherLeaderboard(leaderboard, nombreScores);
    
            //Allocation de mémoire pour créer la grille correspondante à la difficulté choisie
    
            Case **grille = malloc(sizeof(*grille) * tailleGrille);
            for (int i=0; i<tailleGrille; i++) {
                grille[i] = malloc(sizeof(Case) * tailleGrille);
            }
    
            if (grille == NULL) {
                printf("Allocation échouée\n");
                return 0;
            }
    
            partieEnCours = jeu(tailleGrille, grille, nombreMines);
            puts("");
    
            free(grille);
        }
        return 0;
    }
    • Partager sur Facebook
    • Partager sur Twitter
      28 avril 2024 à 14:42:49

      Bonjour ! Pour résoudre ce genre de problème, il faut enquêter, et notamment savoir où, exactement, il boucle. Pour ça, mets des 'printf' là où tu penses que ça boucle.

      Quelque chose comme :

      int choixDifficulte(int *nombreMines) {
          int difficulte;
          printf("Etape 1\n"); 
          printf("Jouons au démineur !\n\nChoisissez votre niveau de difficulté (1, 2, ou 3 pour une partie personnalisée) : ");
          scanf("%d", &difficulte);
          printf("Etape 2\n"); 
      
          //Vérification de la bonne saisie de la difficulté
          while (difficulte != 1 && difficulte != 2 && difficulte != 3) {
              printf("Etape 3.1\n");
              printf("\nErreur, la diffuculté ne peut être comprise qu'entre 1, 2 et 3, nouveau choix : ");
              while (getchar() != '\n'); //On vide le buffer (problème de boucle infinie sinon)
              printf("Etape 3.2\n");
              scanf("%d", &difficulte);
              printf("Etape 3.3\n");
          }
          printf("Etape 4\n");
          if (difficulte == 1) {
              printf("Etape 5\n");
              *nombreMines = 10;
              return 9;
          } else if (difficulte == 2) {
              printf("Etape 6\n");
              *nombreMines = 40;
              return 16;
          } else { //Partie personnalisée
              printf("Etape 7\n");
              int tailleGrille;
       
              //Choix de la taille de la grille
              printf("Etape 8\n");
              printf("\nChoix de la difficulté personnalisée !\nChoisissez une taille de grille entre 3 et 40 : ");
              scanf("%d", &tailleGrille);
              printf("Etape 9\n"); 
              while (tailleGrille < 3 || tailleGrille > 40) {
                  printf("Etape 10.1\n");
                  printf("\nErreur, la taille de la grille doit être comprise entre 3 et 40, nouveau choix : ");
                  while (getchar() != '\n'); //On vide le buffer (problème de boucle infinie sinon)
                  printf("Etape 10.2\n");
                  scanf("%d", &tailleGrille);
                  printf("Etape 10.3\n");        }
       
              // etc. etc. etc.
      
              printf("Etape 15\n"); 
              return tailleGrille;
          }
      }
       

      Le programme affiche quelles étapes ? Selon la réponse, tu sauras où ça coince. Le problème identifié sera alors probablement facile à résoudre.

      Si tu ne comprends toujours pas le problème, tu peux aussi afficher la valeur des variables importantes.

      -
      Edité par robun 28 avril 2024 à 14:43:55

      • Partager sur Facebook
      • Partager sur Twitter
        28 avril 2024 à 15:28:06

        robun a écrit:

        Bonjour ! Pour résoudre ce genre de problème, il faut enquêter, et notamment savoir où, exactement, il boucle. Pour ça, mets des 'printf' là où tu penses que ça boucle.

        Quelque chose comme :

        int choixDifficulte(int *nombreMines) {
            int difficulte;
            printf("Etape 1\n"); 
            printf("Jouons au démineur !\n\nChoisissez votre niveau de difficulté (1, 2, ou 3 pour une partie personnalisée) : ");
            scanf("%d", &difficulte);
            printf("Etape 2\n"); 
        
            //Vérification de la bonne saisie de la difficulté
            while (difficulte != 1 && difficulte != 2 && difficulte != 3) {
                printf("Etape 3.1\n");
                printf("\nErreur, la diffuculté ne peut être comprise qu'entre 1, 2 et 3, nouveau choix : ");
                while (getchar() != '\n'); //On vide le buffer (problème de boucle infinie sinon)
                printf("Etape 3.2\n");
                scanf("%d", &difficulte);
                printf("Etape 3.3\n");
            }
            printf("Etape 4\n");
            if (difficulte == 1) {
                printf("Etape 5\n");
                *nombreMines = 10;
                return 9;
            } else if (difficulte == 2) {
                printf("Etape 6\n");
                *nombreMines = 40;
                return 16;
            } else { //Partie personnalisée
                printf("Etape 7\n");
                int tailleGrille;
         
                //Choix de la taille de la grille
                printf("Etape 8\n");
                printf("\nChoix de la difficulté personnalisée !\nChoisissez une taille de grille entre 3 et 40 : ");
                scanf("%d", &tailleGrille);
                printf("Etape 9\n"); 
                while (tailleGrille < 3 || tailleGrille > 40) {
                    printf("Etape 10.1\n");
                    printf("\nErreur, la taille de la grille doit être comprise entre 3 et 40, nouveau choix : ");
                    while (getchar() != '\n'); //On vide le buffer (problème de boucle infinie sinon)
                    printf("Etape 10.2\n");
                    scanf("%d", &tailleGrille);
                    printf("Etape 10.3\n");        }
         
                // etc. etc. etc.
        
                printf("Etape 15\n"); 
                return tailleGrille;
            }
        }
         

        Le programme affiche quelles étapes ? Selon la réponse, tu sauras où ça coince. Le problème identifié sera alors probablement facile à résoudre.

        Si tu ne comprends toujours pas le problème, tu peux aussi afficher la valeur des variables importantes.

        -
        Edité par robun il y a 42 minutes


        Salut, j'ai déjà fait ça et me suis rendu compte que la fonction ne "s'arrêtait" pas, comme mentionné dans le post. Peut importe la difficulte choisie, mon programme bloque au moment de retourner la valeur de la taille de la grille, et je ne comprends pas pourquoi
        • Partager sur Facebook
        • Partager sur Twitter
          28 avril 2024 à 16:49:52

          Hello,

          Je viens de compiler et tester ton programme. D'abord, bravo, aucune warning. Ensuite, chez moi, ça fonctionne, quelque soit le niveau choisi (sous win10)

          Peut-être un débordement quelque part. Je vais jeter un oeil au code. A plus.

          -
          Edité par edgarjacobs 28 avril 2024 à 16:53:24

          • Partager sur Facebook
          • Partager sur Twitter

          On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent

            28 avril 2024 à 16:49:55

            GreCy21 a écrit:

            ma fonction "choixDifficulte" ne fonctionne plus correctement. Le programme se met à bloquer lors de l'éxecution de celle-ci, comme si le scanf ne récupérait rien alors que je crois qu'il récupère bien les données. Tout était ok depuis que je l'avais codé. Je n'ai aucune piste, 

            J'ai testé ton code, je n'ai pas de blocage sur le choix de difficultés qui semble fonctionner correctement.

            • Partager sur Facebook
            • Partager sur Twitter
            ...
              28 avril 2024 à 17:24:44

              Je ne vois rien de spécial (mais ça ne veut pas dire qu'il n'y a rien), fais tourner sous debugger.

              Il y a une grosse erreur ligne 594: avant de faire free(grille), il faut libérer les grille[i].

              -
              Edité par edgarjacobs 28 avril 2024 à 17:25:38

              • Partager sur Facebook
              • Partager sur Twitter

              On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent

                28 avril 2024 à 18:24:38

                edgarjacobs a écrit:

                Je ne vois rien de spécial (mais ça ne veut pas dire qu'il n'y a rien), fais tourner sous debugger.

                Il y a une grosse erreur ligne 594: avant de faire free(grille), il faut libérer les grille[i].

                -
                Edité par edgarjacobs il y a 34 minutes


                Merci, c'est surement ça ! J'imagine donc que mon programme à "grignoté" la mémoire de mon ordi à mesure que je faisais des test. Est-ce qu'on peut libérer l'espace alloué précédemment ?
                • Partager sur Facebook
                • Partager sur Twitter
                  28 avril 2024 à 18:33:17

                  La désallocation de la mémoire sur le tas faite avec malloc, c'est 1 malloc = 1 free.

                  Tu as 1 malloc suivi de tailleGrille malloc, tu déalloues avec tailleGrille free suivi d' 1 free.

                  • Partager sur Facebook
                  • Partager sur Twitter
                  ...
                    28 avril 2024 à 18:34:36

                    Je n'ai pas testé ton code. J'appuie la suggestion de robbun: fais un printf de la difficulté juste après le scanf.

                    Si le programme afiche la valeur, l'erreur est ailleurs.

                    • Partager sur Facebook
                    • Partager sur Twitter

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

                      28 avril 2024 à 18:35:58

                      rouIoude a écrit:

                      La désallocation de la mémoire sur le tas faite avec malloc, c'est 1 malloc = 1 free.

                      Tu as 1 malloc suivi de tailleGrille malloc, tu déalloues avec tailleGrille free suivi d' 1 free.


                      Yes, j'ai ajouté ça à mon programme, mais ce que je veut faire, c'est nettoyer tout les dégâts fait par les précédents essais. Mon programme bloque toujours après la fonction
                      • Partager sur Facebook
                      • Partager sur Twitter
                        28 avril 2024 à 18:50:03

                        GreCy21 a écrit:

                        Salut, j'ai déjà fait ça et me suis rendu compte que la fonction ne "s'arrêtait" pas, comme mentionné dans le post. Peut importe la difficulte choisie, mon programme bloque au moment de retourner la valeur de la taille de la grille, et je ne comprends pas pourquoi

                        Elle fait quoi, alors ? Tu devrais être plus précis. Par exemple tu disais que ça bloquait et maintenant tu dis qu'il ne s'arrête pas. Il faudrait savoir ! S'il ne s'arrête pas, il va donc jusqu'au bout. C'est ça ? Le programme tourne jusqu'au bout sans te laisser la main ? Bref, je comprends pas.

                        GreCy21 a écrit:

                        Mon programme bloque toujours après la fonction

                         Ah ! Alors, hein, ça bloque ou ça bloque pas ?

                        Bon, OK, ça bloque après la fonction. Tu parles toujours de la fonction choixDifficulte ? En haut c'était dans cette fonction que tu bloquais, donc en fait c'est après son appel, c'est ça ? Eh bien mets des 'printf' après son appel. Et si tu changes encore d'avis, eh bien déterminer où ça bloque et mets des 'printf'. Ce qu'il faut, c'est identifier l'endroit où il y a un problème à la ligne près. Tu dois pouvoir dire : c'est à cette ligne-là précisément qu'il y a un bug. Et alors il y a des chances qu'il suffise de lire cette ligne pour trouver.

                        (Ou alors tu ne sauras jamais, d'autant que le programme marche pour les autres...)

                        • Partager sur Facebook
                        • Partager sur Twitter
                          28 avril 2024 à 18:51:56

                          GreCy21 a écrit:

                          Mon programme bloque toujours après la fonction

                          Après la fonction ?

                          Tu veux dire après la fonction choixUtilisateur ? Je cryais que c'était dans la fonction choixUtilisateur !

                          Il faut être explicite. Peut-tu décrire précisément ce qui ce passe et à quel moment tu rentres dans la boucle sans fin ? Quel affichage tu as à ce moment ?

                          • Partager sur Facebook
                          • Partager sur Twitter
                          ...
                            28 avril 2024 à 19:28:04

                            robun a écrit:

                            GreCy21 a écrit:

                            Salut, j'ai déjà fait ça et me suis rendu compte que la fonction ne "s'arrêtait" pas, comme mentionné dans le post. Peut importe la difficulte choisie, mon programme bloque au moment de retourner la valeur de la taille de la grille, et je ne comprends pas pourquoi

                            Elle fait quoi, alors ? Tu devrais être plus précis. Par exemple tu disais que ça bloquait et maintenant tu dis qu'il ne s'arrête pas. Il faudrait savoir ! S'il ne s'arrête pas, il va donc jusqu'au bout. C'est ça ? Le programme tourne jusqu'au bout sans te laisser la main ? Bref, je comprends pas.

                            GreCy21 a écrit:

                            Mon programme bloque toujours après la fonction

                             Ah ! Alors, hein, ça bloque ou ça bloque pas ?

                            Bon, OK, ça bloque après la fonction. Tu parles toujours de la fonction choixDifficulte ? En haut c'était dans cette fonction que tu bloquais, donc en fait c'est après son appel, c'est ça ? Eh bien mets des 'printf' après son appel. Et si tu changes encore d'avis, eh bien déterminer où ça bloque et mets des 'printf'. Ce qu'il faut, c'est identifier l'endroit où il y a un problème à la ligne près. Tu dois pouvoir dire : c'est à cette ligne-là précisément qu'il y a un bug. Et alors il y a des chances qu'il suffise de lire cette ligne pour trouver.

                            (Ou alors tu ne sauras jamais, d'autant que le programme marche pour les autres...)


                            Justement, c'est ce que j'ai dit plus haut, j'avais déjà regardé ou ça bloquait avec des printf(), et c'est à la sortie de la fonction, elle ne renvoie rien.

                            Voici ce qui se passe :

                            -Je lance le programme et rentre dans la fonction sans erreur,

                            -Le scanf fonctionne, j'ai saisi 1 et la procédure démarre,

                            -On va bien jusqu'au bout comme l'atteste le printf("Fin\n") qui s'affiche dans la console,

                            -La console se bloque, et je peux rentrer des caractères à l'infini sans le moindre changement ni message d'erreur, c'est le cas pour la difficulté 1, 2 et 3.

                            -
                            Edité par GreCy21 28 avril 2024 à 19:45:56

                            • Partager sur Facebook
                            • Partager sur Twitter
                              28 avril 2024 à 20:08:35

                              GreCy21 a écrit:

                              mais ce que je veut faire, c'est nettoyer tout les dégâts fait par les précédents essais

                              Pour ça, pas besoin de te tracasser: l'os l'a fait pour toi lorsque ton programme s'est terminé.

                              Edit: je ne vois pas sur ton printscreen l'affichage des meilleurs scores. Le problème est peut-être dans ces fonctions-là. Si ça fonctionne chez moi, c'est peut-être parce que je n'ai pas le fichier scores.txt. Mets les lignes 576 et 577 en commentaire, pour voir.

                              -
                              Edité par edgarjacobs 28 avril 2024 à 20:20:53

                              • Partager sur Facebook
                              • Partager sur Twitter

                              On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent

                                28 avril 2024 à 20:31:01

                                GreCy21 a écrit:

                                 et c'est à la sortie de la fonction, elle ne renvoie rien.

                                Et comment tu vois qu'elle ne renvois rien ? Parce que une fonction qui retourne un int renverra toujours quelques chose même si ce n'est pas ce que tu souhaites !

                                A mon avis vu que tu arrives jusqu'au return de la fonction le problème ce situe dans le code qui suit l'appel de cette fonction !

                                As tu essayer d'exécuter ton code dans un terminal hors de VS code ?

                                Et tu bien sur que le code que tu as posté est celui qui pose problème ?

                                • Partager sur Facebook
                                • Partager sur Twitter
                                ...
                                  29 avril 2024 à 11:22:52

                                  Bon si je comprends bien, on a une fonction qui demande un niveau de difficulté entre 1 et 3, et en fonction de ça positionne le nombre de mines et la taille de la grille.

                                  pour les niveaux 1 et 2 c'est des paramètres fixes, pour le niveau 3 on laisse l'utilisateur choisir ces paramètres, dans des limites fixées.


                                  Première idée quand je vois ça

                                  int choixDifficulte(int *nombreMines)

                                  c'est qu'on commence à faire des complications avec des données retournées différemment : le nombre de mines passé par adresse, la taille de la grille retournée en résultat. Le nom de la fonction suggère qu'on retourne une difficulté, ben non, c'est une taille. Confusionnant.

                                  (et plus loin il est dit que la fonction ne renvoie rien ? hum hum. Preuve que les complications, ça introduit une confusion, on sait plus ce qu'on fait)

                                  Pour arranger ça : dire que le rôle de la fonction est de retourner des paramètres pour la partie.  En groupant les paramètres dans une structure, comme ça tout est transmis pareil.

                                  Voila ce que ça donne, avec une

                                  • une fonction qui, provisoirement, retourne toujours la même chose sans rien vérifier
                                  • un main qui teste 3 fois (important : il faut prévoir les moyens de tester ce qu'on a écrit. Dès le début. Parce que ça ne marchera pas du premier coup, sauf coup de bol.)
                                  #include <stdio.h>
                                  #include <stdlib.h>
                                  #include <stdbool.h>
                                  
                                  struct parametres_niveau {
                                  	int niveau;               // pendant qu'on y est
                                  	int nb_mines;
                                  	int taille;
                                  };
                                  
                                  struct parametres_niveau demander_parametres() {
                                  	// stub
                                  	printf("Niveau de difficulté ?\n");
                                  	int niveau;
                                  	scanf("%d", & niveau);
                                  	struct parametres_niveau p =  {2, 3, 20};
                                  	return p;
                                  }
                                  
                                  int main()
                                  {
                                  	printf("Tests lecture paramètres\n");
                                  	for (int n = 1; n <= 3; n++) {
                                  		printf("- test #%d\n", n);
                                  		struct parametres_niveau p = demander_parametres();
                                  		printf("=> niveau %d, %d mines, taille %d\n", 
                                  		p.niveau, p.nb_mines, p.taille);
                                  	}
                                  	return EXIT_SUCCESS;
                                  }

                                  Exécution

                                  cc -std=c17 -Wall -Wextra -pedantic -Werror -Wno-unused -D_XOPEN_SOURCE=700 -g    prog.c   -o prog
                                  ./prog
                                  Tests lecture paramètres
                                  - test #1
                                  Niveau de difficulté ?
                                  1
                                  => niveau 2, 3 mines, taille 20
                                  - test #2
                                  Niveau de difficulté ?
                                  34
                                  => niveau 2, 3 mines, taille 20
                                  - test #3
                                  Niveau de difficulté ?
                                  421
                                  => niveau 2, 3 mines, taille 20

                                  C'est absolument parfait, ça transmet bien les paramètres définis dans la fonction demander_parametres.


                                  Seconde étape, on va faire un effort pour le niveau. 1) vérifier qu'il est entre 1 et 3  2) le transmettre en retour

                                  Comme on aura aussi besoin plus loin de saisir des entiers pour le nombre de mines etc en vérifiant que c'est dans des limites indiquées, on fait une fonction qui s'en occupe.

                                  La fonction demander_parametres devient

                                  struct parametres_niveau demander_parametres()
                                  {
                                      int niveau = demander_entier("Donnez le niveau", 1, 3);
                                      struct parametres_niveau p =  {niveau, 3, 20};  // provisoire
                                      return p;
                                  }



                                  et on teste avec  abc, 0, 4, 1, 2 et 3

                                  Tests lecture paramètres
                                  - test #1
                                  Donnez le niveau (entre 1 et 3) ?abc
                                  /!\ un nombre svp. Donnez le niveau (entre 1 et 3) ?0
                                  /!\ trop petit. Donnez le niveau (entre 1 et 3) ?4
                                  /!\ trop grand. Donnez le niveau (entre 1 et 3) ?1
                                  => niveau 1, 3 mines, taille 20
                                  - test #2
                                  Donnez le niveau (entre 1 et 3) ?2
                                  => niveau 2, 3 mines, taille 20
                                  - test #3
                                  Donnez le niveau (entre 1 et 3) ?3
                                  => niveau 3, 3 mines, taille 20

                                  Ah oui, la fonction qui demande un nombre :

                                  int demander_entier(char *message, int min, int max)
                                  {
                                      while (true) {
                                          printf("%s (entre %d et %d) ?", message, min, max);
                                  		
                                          int reponse;
                                          if (scanf("%d", &reponse) != 1) {
                                  			printf("/!\\ un nombre svp. ");
                                  			while (fgetc(stdin) != '\n') {};  // mange la fin de ligne
                                  			continue;                         // reprise de la boucle
                                  		}
                                  		if (reponse < min) {
                                  			printf("/!\\ trop petit. ");
                                  			continue;
                                  		}
                                  		if (reponse > max) {
                                  			printf("/!\\ trop grand. ");
                                  			continue;
                                  		}
                                  		return reponse;
                                      }
                                  }
                                  


                                  [la structure   boucle infinie + continue(s) + return, c'est pratique pour avoir plein de tests et reposer la question (continuer la boucle) si un d'eux échoue, sans avoir une imbrication monstrueuse de tous les tests.]

                                  Bon, on commence à voir le bout : reste plus qu'à s'occuper des différents niveaux, y en a pas trop, un switch parait bien indiqué

                                  struct parametres_niveau demander_parametres()
                                  {
                                      struct parametres_niveau p;
                                      p.niveau = demander_entier("Donnez le niveau", 1, 3);
                                      switch (p.niveau) {
                                      case 1:
                                          p.nb_mines = 10;
                                          p.taille   = 9;
                                          break;
                                      case 2:
                                          p.nb_mines = 40;
                                          p.taille   = 16;
                                          break;
                                      case 3:
                                          p.taille = demander_entier("Taille de la grille", 3, 40);
                                          int max_mines = p.taille * p.taille - 1;
                                          p.nb_mines = demander_entier("Nombre de mines", 1, max_mines);
                                      }
                                  
                                      return p;
                                  }

                                  Test :

                                  Tests lecture paramètres
                                  - test #1
                                  Donnez le niveau (entre 1 et 3) ?1
                                  => niveau 1, 10 mines, taille 9
                                  - test #2
                                  Donnez le niveau (entre 1 et 3) ?2
                                  => niveau 2, 40 mines, taille 16
                                  - test #3
                                  Donnez le niveau (entre 1 et 3) ?3
                                  Taille de la grille (entre 3 et 40) ?10
                                  Nombre de mines (entre 1 et 99) ?33
                                  => niveau 3, 33 mines, taille 10


                                  Conclusion : de préférence, écrivez vos programmes par étapes, par petits bouts en vous donnant des objectifs partiels, et les moyens de vérifier que ce que vous avez écrit marche, à chaque étape. Et les petits bouts de votre code auront été testés un par un.

                                  Les objectifs partiels étant plus faciles à réaliser, vous serez contents que ça marche plus souvent. Ça tombe bien, en général, on aime bien être content, et les succès partiels répétés renforcent la motivation.

                                  ---

                                  PS pendant que j'y suis, je vois la séquence de 5 appels à printf

                                   printf("[");
                                   couleur(VIOLET);
                                   printf("X");
                                   couleur(RESET);
                                   printf("]");
                                               

                                  (et une dizaine de séquence du même genre)

                                  avec la macro et les définitions

                                  #define RESET "\033[0m"
                                  #define ROUGE "\033[31m"
                                  #define VERT "\033[32m"
                                  #define JAUNE "\033[33m"
                                  #define BLEU "\033[34m"
                                  #define VIOLET "\033[35m"
                                  #define BLEUCYAN "\033[36m"
                                  #define couleur(couleur) printf(couleur)


                                  Bref, il s'agit de faire un printf de 5 chaines de caractères.

                                  Un truc à savoir, c'est qu'en C, une chaîne de caractères littérale peut être écrite en plusieurs morceaux,  donc

                                  printf("Hello, "  
                                         "world !"  
                                         "\n");
                                  

                                  (je saute des lignes pour qu'on voie bien) c'est exactement la même chose que

                                  printf("Hello, world!\n");
                                  

                                  Ce qui trouve une application directe ici, les 5 printf ça peut s'écrire plus simplement en un seul

                                  printf("[" VIOLET  "X"  RESET "]");
                                  

                                  ce qui est quand même plus court.

                                  Aussi, on doit pouvoir éviter d'avoir 9 cas du case grâce à un tableau

                                  char *representation[] = {
                                       "[" BLEU_CYAN  "1"  RESET "]",
                                       "[" BLEU       "2"  RESET "]",
                                       ....
                                  };
                                   
                                  






                                  -
                                  Edité par michelbillaud 30 avril 2024 à 11:58:58

                                  • Partager sur Facebook
                                  • Partager sur Twitter

                                  Fonction qui tourne à l'infini

                                  × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                  • Editeur
                                  • Markdown