Partage
  • Partager sur Facebook
  • Partager sur Twitter

Lecture dans un fichier

Activité TP mystère

Sujet résolu
    22 novembre 2019 à 20:31:45

    Bonjour, je suis en train de faire la prremière activité mais quand j'essaye de lire dans un fichier, il ne me lit rien. Pourquoi ?

    string lire_fichier()
    {
       ifstream fichier("dico/dico.txt");  //Ouverture d'un fichier en lecture
       string mot, ligne;
       int taille = 0, alea, i;
       if(fichier)
       {
          while(getline(fichier, ligne))
             taille++;
          alea = rand() % taille;
          cout << taille << "/" << alea << endl;
          for(i = 0; i <= alea; i++)
          {
             getline(fichier, mot);
          }
          cout << "mot : " << mot<< endl;
       }
       else
       {
           cout << "ERREUR: Impossible d'ouvrir le fichier en lecture." << endl;
           mot = "LONGEVITE"; //Définit un mot au cas où le fichier n'est pas lu.
       }
       return mot;
    }
    


    Merci de votre  réponse.

    • Partager sur Facebook
    • Partager sur Twitter
      22 novembre 2019 à 21:34:40

      Le problème c'est que ton while(getline ... va fatalement arriver à la fin du fichier, il faut donc "reconfigurer" le flux avant d'aller lire le mot, sinon tu mets ton flux en erreur et du coup tu ne lis rien puisque ton flux est en erreur, cette manipulation se fait avec la fonction seek qui correspond au type de ton flux. Quoi qu'il en soit, quelques faits:

      • Le temps d'accès moyen à une information en RAM est de l'ordre de 10^-9 seconde
      • Le temps d'accès moyen à une information dans un fichier est de l'ordre de 10^-3 seconde

      Cela veut dire qu'un accès RAM est environ un million de fois plus rapide.

      La langue anglaise passe pour être la langue qui possède le vocabulaire le plus riche (environ 350000 mots, le français est très proche avec pas loin de 300000 mots) en considérant qu'un mot fait en moyenne 10 lettres, ce qui est très pessimiste, la plupart des mots sont bien plus courts, tu obtiens une charge mémoire de 3 Mo. Pour être plus réaliste on ne va pas prendre 10 lettres par mot de moyenne mais 48 lettres (la différence peut être vue comme des frais de gestion...). 350000 * 48 = 16 800 000, soit un peu moins de 16 Mo, autant dire pas grand chose sur un PC moderne. Si tu as tout en mémoire, ça ne te coûte pas bien cher en RAM (environ 16 Mo), mais le gros gain, c'est que tu n'a plus aucune lecture fichier à faire, tu lis ton fichier en bloc au début et puis basta, tu bosses en RAM.

      L'autre avantage, c'est que lors de la lecture de ton fichier, tu peux organiser ton stockage en RAM, et c'est là que ça devient encore plus intéressant, parce que tu vas stocker ton dictionnaire dans un tableau, un std::vector<std::string>>, et du coup pour choisir un mot, c'est facile, tu tire un nombre au sort entre 0 et la taille du vector -1 et le tour est joué, le résultat c'est l'indice du mot choisi dans ton tableau. Tu peux même encore faire mieux, tu mélange ton tableau au début, et l'indice du mot choisi à chaque partie devient le nombre de partie jouées (modulo le nombre de mots du dictionnaire), quand le nombre de parties jouées est égal au nombre de mots contenus dans le dictionnaire, tu mélanges le dictionnaire, et tu remet le compteur de parties jouées à 0. C'est nettement plus simple que ton bazar, parce que tirer au sort un nombre entre 0 et la taille d'un tableau, c'est quand même plus simple que ton bazar ;) et en plus c'est plus rapide, si tu pousses jusqu'à l'amélioration, c'est encore plus brutal, tirer un nouveau mot au sort revient à incrémenter un compteur, c'est encore plus simple ;)

      PS et puis en c++ moderne, on n'utilise plus srand/rand, on va lire la doc de <random>, qui contient tout ce qu'il faut pour gérer des aléas 

      -
      Edité par int21h 22 novembre 2019 à 21:49:31

      • Partager sur Facebook
      • Partager sur Twitter
      Mettre à jour le MinGW Gcc sur Code::Blocks. Du code qui n'existe pas ne contient pas de bug
        23 novembre 2019 à 15:59:44

        Comment mélanger l'odre du tableau ?

        Avec le tableau, cela doit entrainer un buffer overflow car ça me fait ça :

        string melangerLettres(string mot)
        {
           string melange;
           int position(0);
        
        
           //Tant qu'on n'a pas extrait toutes les lettres du mot
           while (mot.size() != 0)
           {
              //On choisit un numéro de lettre au hasard dans le mot
              position = rand() % mot.size();
              //On ajoute la lettre dans le mot mélangé
              melange += mot[position];
              //On retire cette lettre du mot mystère
              //Pour ne pas la prendre une deuxième fois
              mot.erase(position, 1);
              cout << "mélange : " << melange << endl;
            }
        
           //On renvoie le mot mélangé
           return melange;
        }
        
        void jouer()
        {
           string motMystere, motMelange, motUtilisateur;
           int coups_restants = 5;
           //Initialisation des nombres aléatoires
        
           //1 : On demande de saisir un mot
           motMystere = lire_fichier();
        
           //2 : On récupère le mot avec les lettres mélangées dans motMelange
           motMelange = melangerLettres(motMystere);
        
           //3 : On demande à l'utilisateur quel est le mot mystère
           cout << "Vous avez " << coups_restants << " essais." << endl;
           do
           {
              cout << endl << "Quel est ce mot ? " << motMelange << endl;
              cin >> motUtilisateur;
        
              if (motUtilisateur == motMystere)
              {
                 cout << "Bravo !" << endl;
              }
              else
              {
                 coups_restants--;
                 cout << "Ce n'est pas le mot !" << endl;
                 if (coups_restants > 0)
                    cout << "Il ne vous reste que " << coups_restants << " coups pour trouver la solution" << endl;
                 else
                    cout << "Vous avez perdu..." << endl;
              }
           }while (motUtilisateur != motMystere && coups_restants > 0);
           //On recommence tant qu'il n'a pas trouvé
        }
        
        string lire_fichier()
        {
           vector <string> dico(0);
           ifstream fichier("dico/dico.txt");  //Ouverture d'un fichier en lecture
           string ligne, mot;
           if(fichier)
           {
              while(getline(fichier, ligne))
                 dico.push_back(ligne);
              mot = dico[0];
              cout << mot << endl;
              
           }
           else
           {
               cout << "ERREUR: Impossible d'ouvrir le fichier en lecture." << endl;
           }
           return mot;
        }
        ABAISSA
        mélange : I
        mélange : IS
        mélange : ISA
        mélange : ISAA
        mélange : ISAAB
        Aélange : ISAAB
        ASlange : ISAAB
        Vous avez 5 essais.
        
        ASel est ce mot ? ISSAB
        

        Le mot empiète sur les strings du cout ...


        -
        Edité par EnderRayquaza 23 novembre 2019 à 16:24:03

        • Partager sur Facebook
        • Partager sur Twitter
          23 novembre 2019 à 16:18:09

          Bonjour,

          Rayquaza Delta a écrit:

          Comment mélanger l'ordre du tableau ?

           ... ou peut-être tirer aléatoirement une ligne, non?

          Bien cordialement



          • Partager sur Facebook
          • Partager sur Twitter
            23 novembre 2019 à 16:21:47

            De la même façon que tu mélange un jeu de cartes ;) Si je prends un jeu de cartes, on peut faire l'analogie avec un tableau. La première carte (la première case du tableau) est la carte  qui se trouve au dessus du jeu, si je le prend face cachée (supposons que cette carte est l'as de pique). Je prends le jeu de cartes est je le mélange bien, il est peu probable que la première carte soit encore l'as de pique. Si je défile tout mon jeu de carte, je vais fatalement retomber sur mon as de pique...

            Un autre exemple qui te parleras peut être plus, lorsque tu mélanges les lettres d'un mot, que fais tu? tu mélanges un tableau de lettres (un string n'est techniquement pas autre chose q'un tableau de lettres), tu échanges aléatoirement la lettre d'une "case" de ton tableau avec le celle d'une autre case. Pourquoi diable voudrais tu qu'il en aille différemment avec  un tableau de mots... Si tu peux le faire avec des lettres, alors tu peux le faire avec des mots, la méthode est exactement la même, il n'y a que la nature des données qui change.

            Quand je mélange un mot, je change la place des lettres, quand je mélange un dictionnaire, je change la place des mots ;)

            C++ implémente quatre paradigmes, l'impératif (c'est celui avec lequel tu te débats) le polymorphisme d'inclusion (qu'on appelle vulgairement la Programmation Orientée Objet), et le polymorphisme paramétrique (qu'on appelle vulgairement les templates). Si tu pousses mon petit raisonnement un peu plus loin, tu vas tomber dans le polymorphisme paramétrique, et écrire une seule fonction un peu spéciale (en fait ce n'est pas une fonction mais un modèle, template en anglais ...) qui est capable de mélanger n'importe quel tableau quel que soit son contenu, bienvenue dans le polymorphisme paramétrique.

            Si tu pousses le raisonnement encore plus loin, tu pourrais même envisager de changer la façon de mélanger, et là tu tombes dans le quatrième paradigme, sans aucun doutes le plus complexe à appréhender et le plus fascinant (mais pas forcément le plus utile au quotidien ): La méta-programmation, tu n'écris plus le programme, tu donnes au compilateur les éléments pour qu'il écrive le programme...

            -
            Edité par int21h 23 novembre 2019 à 17:17:46

            • Partager sur Facebook
            • Partager sur Twitter
            Mettre à jour le MinGW Gcc sur Code::Blocks. Du code qui n'existe pas ne contient pas de bug
              23 novembre 2019 à 18:06:02

              Dedeun a écrit:

              Bonjour,

              Rayquaza Delta a écrit:

              Comment mélanger l'ordre du tableau ?

               ... ou peut-être tirer aléatoirement une ligne, non?

              Bien cordialement

              int21h a écrit:

              [...]Tu peux même encore faire mieux, tu mélange ton tableau au début, et l'indice du mot choisi à chaque partie devient le nombre de partie jouées (modulo le nombre de mots du dictionnaire), quand le nombre de parties jouées est égal au nombre de mots contenus dans le dictionnaire, tu mélanges le dictionnaire, et tu remet le compteur de parties jouées à 0. C'est nettement plus simple que ton bazar, parce que tirer au sort un nombre entre 0 et la taille d'un tableau, c'est quand même plus simple que ton bazar ;) et en plus c'est plus rapide, si tu pousses jusqu'à l'amélioration, c'est encore plus brutal, tirer un nouveau mot au sort revient à incrémenter un compteur, c'est encore plus simple ;)[...]


              Voilà pourquoi mélanger le tableau.

              Mais comment supprimer l'element i du tableau ?

              • Partager sur Facebook
              • Partager sur Twitter
                23 novembre 2019 à 20:21:48

                Mais pourquoi veux tu supprimer un élément du tableau? J'ai parlé de le mélanger, pas de supprimer des éléments, parce que pour le coup, supprimer un élément dans un vector, ça peut coûter un bras en terme de performances...

                -
                Edité par int21h 23 novembre 2019 à 20:22:17

                • Partager sur Facebook
                • Partager sur Twitter
                Mettre à jour le MinGW Gcc sur Code::Blocks. Du code qui n'existe pas ne contient pas de bug
                  23 novembre 2019 à 21:02:36

                  Parce que sinon on peut tirer 2 fois le même mot et la boucle est infinie :

                        //On retire cette lettre du mot mystère
                        //Pour ne pas la prendre une deuxième fois
                        mot.erase(position, 1);

                  -
                  Edité par EnderRayquaza 23 novembre 2019 à 21:04:49

                  • Partager sur Facebook
                  • Partager sur Twitter
                    23 novembre 2019 à 23:05:35

                     Bien sûr que tu peux tirer deux fois le même mot, ce n'est pas un problème, si ton dictionnaire est assez grand, ce sera très rare et à la limite, ça ajoutera du piment au jeu, parce que le joueur ne saura pas que le mot qu'il doit deviner est le même que celui qu'il a du deviner une heure avant ;) 

                    C'est une question de probabilité, si je prends par exemple le loto, est ce que la française des jeux verrouille le tirage pour qu'une combinaison déjà sortie ne puisse plus sortir? Bien sûr que non, si elle le faisait, elle se retrouverait face à des joueurs "expérimentés" qui ne joueraient plus que les combinaisons qui ne sont jamais sorties, et petit à petit, ces joueurs là augmenteraient leurs chances de gagner, vu que le nombre de combinaisons gagnantes possibles diminuerait. En théorie des jeux/probabilités on appelle ça le tirage avec ou sans remise. 

                    • Le tirage avec remise, je ne tiens pas compte de ce qui c'est passé avant, on remet le compteur à 0 à chaque tirage, ce qui implique que la probabilité que j'ai deux "tirages" identique est non nulle, donc ça peut se produire. Le loto fonctionne selon cette logique, l'ensemble des combinaisons possible est si grand que la probabilité que la même combinaison sorte deux fois est infime (sur un temps court, mais plus le nombre de tirages augmente, plus cette probabilité augmente), si petite soit elle, elle n'est pas nulle, donc ça pourrait se produire, et si on pouvait assister au tirage du loto pendant quelques millions d'années, on verrait plusieurs tirage gagnants apparaître plusieurs fois., Si on pouvait assister au tirage du loto, pendant des milliards d'années, c'est la probabilité qu'une combinaison qui n'est jamais sortie, sorte qui deviendrait de plus en plus infime, puis nulle ( le jour où elle sortirait).
                    • Le tirage sans remise, c'est par exemple ce qui va se passer lorsque tu joues à un jeu de cartes comme le tarot, la belote ou le bridge, lorsqu'une carte est jouée, elle est jouée, elle ne sera pas rejouée dans la partie, sinon on peut légitimement affirmer qu'il y a un tricheur. Si je considère un jeu de 52 cartes standard, la probabilité pour qu'une carte précise soit jouée est de 1/52, au fil du jeu, soit la carte à été jouée auquel cas la probabilité pour qu'elle soit jouée à nouveau est nulle, soit elle n'a pas encore été jouée et dans ce cas, la probabilité qu'elle soit jouée est 1 / k où k est le nombre de cartes restant à jouer. Ce n'est pas pour rien que les bons joueurs de tarot, belote, bridge comptent les cartes qui ont été jouées, ça leur donne une information déterminante sur les cartes qui sont dans les mains de leurs adversaires.

                    -
                    Edité par int21h 23 novembre 2019 à 23:17:35

                    • Partager sur Facebook
                    • Partager sur Twitter
                    Mettre à jour le MinGW Gcc sur Code::Blocks. Du code qui n'existe pas ne contient pas de bug
                      23 novembre 2019 à 23:08:35

                      Salut

                      Comme disais int21h :

                      Le temps d'accès moyen à une information en RAM est de l'ordre de 10^-9 seconde Le temps d'accès moyen à une information dans un fichier est de l'ordre de 10^-3 seconde Cela veut dire qu'un accès RAM est environ un million de fois plus rapide.

                      L'autre avantage, c'est que lors de la lecture de ton fichier, tu peux organiser ton stockage en RAM, et c'est là que ça devient encore plus intéressant, parce que tu vas stocker ton dictionnaire dans un tableau, un std::vector>

                      Et voici l'implémentation de ta fonction lire_fichier() :

                      string lire_fichier()
                      {
                         vector <string> dico(0);
                         ifstream fichier("dico/dico.txt");  //Ouverture d'un fichier en lecture
                         string ligne, mot;
                         if(fichier)
                         {
                            while(getline(fichier, ligne))
                               dico.push_back(ligne);
                            mot = dico[0];
                            cout << mot << endl;
                             
                         }
                         else
                         {
                             cout << "ERREUR: Impossible d'ouvrir le fichier en lecture." << endl;
                         }
                         return mot;
                      }

                      L'idée justement c'est de lire l'intégralité de ton fichier et de stocker chaque mot de ton dictionnaire dans un std::vector<std::string> une fois pour toutes.

                      Là dans ton code tu utiliseras à chaque fois cette fonction pour choisir un mot donc tu liras à chaque fois tout le fichier.

                      Sans parler que ta fonction ne lit pas vraiment le fichier, elle choisit un mot.

                      Je t'écris la fonction qui permet de charger tout ton fichier sans un std::vector<std::string> étant donné que tu avais déjà coder une bonne partie du travail :

                      std::vector<std::string> chargerFichier(std::string const & chemin) // L'adresse du fichier en paramètre, c'est plus souple que de l'implanté directement dans ta fonction
                      {
                          std::ifstream fichier {chemin};
                          
                          if (!fichier) // Si il ne peut pas ouvrir le fichier, le programme s'arrête, pourquoi continuer ?
                          {
                              throw std::runtimme_error {"Impossible d'ouvrir le fichier a l'adresse : " + chemin};
                          }
                          
                          std::string ligne {};
                          std::vector<std::string> liste {};
                          
                          while (std::getline(fichier, ligne))
                          {
                              liste.push_back(ligne);
                          }
                          
                          return liste;
                      }

                      A partir de là, plus besoin de lire ton fichier, tu as tout dans ton std::vector<std::string> et tu peux maintenant t'amuser à gérer ton dictionnaire de la façon que tu veux.

                      • Partager sur Facebook
                      • Partager sur Twitter
                        24 novembre 2019 à 13:57:57

                        Merci mais ça ne règle tjrs pas le problème duBuffer Overflow...
                        • Partager sur Facebook
                        • Partager sur Twitter
                          24 novembre 2019 à 16:08:54

                          À quoi ressemble le code maintenant ?

                          De plus, la stl et le compilateur dispose de suffisamment d'outils pour détecter rapidement et précisément où se situe une erreur sans nécessairement sortir le débugueur: le mode debug de la STL et les sanitizers des compilateurs (il y en a d'autres). Les options à utiliser à la compilation sont -fsanitize=address -fsanitize=undefined -D_GLIBCXX_DEBUG pour gcc.

                          • Partager sur Facebook
                          • Partager sur Twitter
                            24 novembre 2019 à 16:32:29

                            #include <iostream>
                            #include <fstream>
                            #include <string>
                            #include <ctime>
                            #include <cstdlib>
                            #include <vector>
                            
                            using namespace std;
                            
                            string melangerLettres(string mot);
                            void jouer();
                            std::vector<std::string> chargerFichier(std::string const & chemin);
                            
                            int main()
                            {
                               int rejouer = 1;
                               srand(time(0));
                               do
                               {
                                  jouer();
                                  cout << "Voulez vous rejouer ? (0/1)" << endl;
                                  cin >> rejouer;
                                  if (rejouer == 1)
                                     cout << "Début d'une nouvelle partie..." << endl << endl;
                                  
                               }while(rejouer == 1);
                               cout << "Fin de la partie." << endl;
                                return 0;
                            }
                            
                            string melangerLettres(string mot)
                            {
                               string melange;
                               int position(0);
                            
                            
                               //Tant qu'on n'a pas extrait toutes les lettres du mot
                               while (mot.size() != 0)
                               {
                                  //On choisit un numéro de lettre au hasard dans le mot
                                  position = rand() % mot.size();
                                  //On ajoute la lettre dans le mot mélangé
                                  melange += mot[position];
                                  //On retire cette lettre du mot mystère
                                  //Pour ne pas la prendre une deuxième fois
                                  mot.erase(position, 1);
                                  cout << "mélange : " << melange << endl;
                                }
                            
                               //On renvoie le mot mélangé
                               return melange;
                            }
                            
                            void jouer()
                            {
                               vector<string> liste {};
                               string motMystere, motMelange, motUtilisateur;
                               int coups_restants = 5;
                               //Initialisation des nombres aléatoires
                            
                               //1 : On demande de saisir un mot
                               liste = chargerFichier("dico/dico.txt");
                               motMystere = liste[0];
                               cout << motMystere << endl;
                            
                               //2 : On récupère le mot avec les lettres mélangées dans motMelange
                               motMelange = melangerLettres(motMystere);
                            
                               //3 : On demande à l'utilisateur quel est le mot mystère
                               cout << "Vous avez " << coups_restants << " essais." << endl;
                               do
                               {
                                  cout << endl << "Quel est ce mot ? " << motMelange << endl;
                                  cin >> motUtilisateur;
                            
                                  if (motUtilisateur == motMystere)
                                  {
                                     cout << "Bravo !" << endl;
                                  }
                                  else
                                  {
                                     coups_restants--;
                                     cout << "Ce n'est pas le mot !" << endl;
                                     if (coups_restants > 0)
                                        cout << "Il ne vous reste que " << coups_restants << " coups pour trouver la solution" << endl;
                                     else
                                        cout << "Vous avez perdu..." << endl;
                                  }
                               }while (motUtilisateur != motMystere && coups_restants > 0);
                               //On recommence tant qu'il n'a pas trouvé
                            }
                            
                            std::vector<std::string> chargerFichier(std::string const & chemin) // L'adresse du fichier en paramètre, c'est plus souple que de l'implanté directement dans ta fonction
                            {
                               std::ifstream fichier {chemin};
                                 
                               if (!fichier) // Si il ne peut pas ouvrir le fichier, le programme s'arrête, pourquoi continuer ?
                               {
                                  throw std::runtime_error {"Impossible d'ouvrir le fichier a l'adresse : " + chemin};
                               }
                                 
                               std::string ligne {};
                               std::vector<std::string> liste {}, liste_melange {};
                                 
                               while (std::getline(fichier, ligne))
                               {
                                   liste.push_back(ligne);
                               }
                               
                               int pos, taille;
                               taille = liste.size();
                               while(taille != 0)
                               {
                                  //On choisit un mot au hasard dans la liste
                                  pos = rand() % liste.size();
                                  //On ajoute le mot dans la liste mélangée
                                  liste_melange.push_back(liste[pos]);
                                  taille--;
                               }
                                 
                               return liste_melange;
                            }
                            

                             Quand j'ajoute ta ligne à ma commande, le fichier ne s'éxécute plus.:(

                            -
                            Edité par EnderRayquaza 24 novembre 2019 à 16:41:26

                            • Partager sur Facebook
                            • Partager sur Twitter
                              24 novembre 2019 à 18:21:10

                              Tu as loupé une étape ;)

                              • Je charge le contenu du fichier dans un vector au début du programme, ça je le fait une seule fois au début du programme, une fois que c'est fait, exit le fichier, on s'en fout, on ne l'utilise plus, on a le vector qui est dans la mémoire et on ne plus va bosser qu'avec lui. 
                              • Pour tirer un mot au sort, je tape dans le vector, je connais sa taille, les indices de tableau commencent à 0 donc je tire un nombre au sort ente 0 et la taille du vector -1 (parce que ça commence à 0), jamais de la vie je ne vais aller relire le fichier, le nombre obtenu par tirage au sort me donne directement la "case" du vector qui contient le mot tiré au sort. 

                              La variante, consiste aussi à charger le contenu du fichier dans un vector, et c'est pareil, une fois qu'on a fait ça, exit le fichier, on n'en a plus besoin, on ne va plus bosser qu'avec le vector qui est en mémoire. La subtilité de la variante, c'est qu'au lieu tirer au sort un nombre entre 0 et la taille du vector -1, je vais choisir le mot dans le vector, dont l'indice est le nombre de parties jouées, à la première partie, je vais prendre le mot d'indice 0, à la seconde, le mot d'indice 1...  La subtilité du truc, c'est qu'après avoir chargé le dictionnaire, je vais mélanger le vector, si bien qu'à chaque fois que je vais lancer le jeu, le mélange sera différent, donc l'ordre de sortie des mots sera différent.

                              En programmation, il y a un principe tout à fait fondamental: le principe de responsabilité unique. Ce principe tu le connais déjà, il se cache derrière plein de dictons, proverbes et maximes, de la plus impériale Diviser pour régner à la plus humble: Je ne sais faire qu'une seule chose mais je la fais bien.

                              Par devant tout le reste, tu ne dois jamais t'écarter de ce principe lorsque tu programmes.  Je ne mélange pas en même temps que je charge, d'abord je charge (une responsabilité), puis éventuellement je mélange (une autre responsabilité). Si tu veux devenir un bon programmeur, c'est comme ça que tu dois penser ton code, pas autrement.

                              -
                              Edité par int21h 24 novembre 2019 à 19:00:59

                              • Partager sur Facebook
                              • Partager sur Twitter
                              Mettre à jour le MinGW Gcc sur Code::Blocks. Du code qui n'existe pas ne contient pas de bug
                                26 novembre 2019 à 19:02:01

                                Quelle étape ai-je loupé ? Je ne réutilise pas le fichier, et je mélage le vecteur...
                                • Partager sur Facebook
                                • Partager sur Twitter
                                  27 novembre 2019 à 10:14:33

                                  Ta fonction melangerLettre peut s'écrire en une ligne avec les fonctions appropriées de <algorithm> et <random>.
                                  • Partager sur Facebook
                                  • Partager sur Twitter

                                  git is great because Linus did it, mercurial is better because he didn't.

                                    28 novembre 2019 à 5:38:18

                                    Je charge le fichier en mémoire puis éventuellement je le mélange (2 responsabilités) + principe de responsabilité unique = 2 fonctions (au minimum, parce que si une tâche est trop complexe, je la découpe...).

                                    markand, fait remarquer que le mélange des lettres peut se faire en une ligne, en suivant sa remarque, le mélange du dictionnaire se fait aussi en une ligne (qui sera pratiquement la même).

                                    En c++, ne déclare jamais tes variables en avance, ça ne sert à rien, ça encombre la pile, et c'est une source d'erreur. Déclare les toujours au plus près de leur première utilisation, en faisant ça, tu pourras quasiment toujours les initialiser directement avec la bonne valeur, tu réduis le risque d'utiliser une variable qui ne serait pas correctement initialisée, un masquage de variable ou un recyclage malheureux. En plus comme elle est déclarée tout près, tu auras la déclaration sous les yeux quand tu vas l'utiliser.

                                    Prends aussi soin de bien choisir les noms des objets (variables, fonctions, classes...). Les noms doivent parler, là tu es en pleine écriture de ton programme, tout est net et clair dans ta tête, mais dans 6 mois, quand tu devras revenir dessus, pour corriger un bug ou l'améliorer, ou simplement te rafraîchir la mémoire, tout ne sera pas aussi clair et net... Garde bien à l'esprit, que pour un vrai programme (pas un exercice), tu passeras probablement plus de temps à le relire, qu'à l'écrire (pour le corriger, l'améliorer, l'étendre) et que les relecture pourront s'étendre sur des mois, voir des années.

                                    Prend bien soin du découpage 

                                    void jouer()
                                    {
                                       auto dico = chargerFichier("dico/dico.txt");
                                       melangerDico(dico);   
                                       int compteurParties{};
                                    
                                       do {
                                          jouerPartie(dico,compteurParties);
                                          ++compteurParties;
                                     
                                       } while(proposerUneAutrePartie())
                                    
                                       /* ou avec un for:
                                    
                                          auto dico = chargerFichier("dico/dico.txt");
                                          melangerDico(dico);   
                                    
                                          for(auto compteurParties = 0; proposerUneAutrePartie();++compteurParties){
                                             jouerPartie(dico,compteurParties);
                                          }
                                          
                                       */
                                    }
                                     

                                    Enfin ta procédure de mélange du dictionnaire a une fâcheuse tendance à dupliquer les mots  et donc à en supprimer, puisque la taille est constante. Rien ne te garantit que ton appel  rand() % list.size() ne sortira pas plusieurs fois la même valeur et par conséquent, que certaines valeurs de l'intervalle ne sortiront pas. La solution suggérée par markand permet de régler ce problème de façon élégante en évitant les limitations de rand (rand sort une valeur comprise entre 0 et RAND_MAX qui vaut ordinairement 32765, donc si ton dictionnaire contient plus de 32765 mots, ton mélange sera... partiel).

                                    Néanmoins, si tu tiens absolument à mélanger par toi même, il serait plus avisé d'échanger les mots du dictionnaire en utilisant std::swap:

                                    std::vector<std::string> dico{"un","deux","trois"};
                                    
                                    for(auto const & s : dico){
                                       std::cout << s << std::endl;
                                    }
                                    
                                    std::cout << "Echange" << std::endl; 
                                    std::swap(dico[0],dico[1]); 
                                    
                                    for(auto const & s : dico)
                                    { 
                                        std::cout << s << std::endl; 
                                    }
                                    

                                    -
                                    Edité par int21h 28 novembre 2019 à 5:49:06

                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                    Mettre à jour le MinGW Gcc sur Code::Blocks. Du code qui n'existe pas ne contient pas de bug

                                    Lecture dans un fichier

                                    × 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