Problème avec un petit jeu de mot mystère [Résolu]

Signaler
Messages postés
493
Date d'inscription
vendredi 9 décembre 2011
Statut
Membre
Dernière intervention
7 février 2016
-
Messages postés
493
Date d'inscription
vendredi 9 décembre 2011
Statut
Membre
Dernière intervention
7 février 2016
-
Bonjour,
J'ai commencé un tutoriel sur le C++ et je suis en train de coder un petit jeu consistant à trouver un mot mystère en console. J'ajoute des fonctionnalités au fur et à mesure et je bloque sur une partie.

En gros, il y a un fichier dictionnaire et le programme vas chercher un mot au hasard, le mélange et demande au joueur de deviner le mot mélangé. Mais voilà, je ne veux pas qu'un même mot revienne plus d'une fois avant que tout les mots du fichier dictionnaire aient étés épuisés.

J'ai essayé, pour cela, de mettre dans un tableau dynamique les numéros de ligne tirés au hasard (j'ai au préalable déterminé automatiquement combien de lignes il y a dans le fichier dictionnaire) et je teste ensuite si une case a la même valeur qu'une autre. Cela fonctionne, mais est lent, puisque si une case à bien la même valeur qu'une autre, le programme reset le tableau et y remet des valeurs au hasard jusqu'à ce qu'elles soient toutes différentes. C'est très long dès q'il y à 15 mots et plus dans le fichier dictionnaire. On est loin du 60 000 mots de la langue française, plus le pluriel et les conjugaisons...

J'ai ensuite essayé une autre méthode, consistant à tirer un numéro de ligne au hasard et à vérifier s'il se trouve dans le tableau. Si oui, il tire à nouveau un numéro de ligne, vérifie s'il s'y trouve, et etc... Mais je n'y arrive pas, et je bloque sur ce problème depuis quelques jours.
En fait, je me suis fait un programme test qui fait seulement ce qui est expliqué plus haut.

En gros, je me demandais si vous pourriez m'aider à régler ce problème, de quelques façons que ce soit...

P.S. C'est mon premier message sur ce forum, dites-le moi si je fait quelque chose de pas correct... Si je dois fournir quoi que ce soit, ou je-sais-pas-quoi...

Cordialement,
Alain2131.

:)

13 réponses

Messages postés
493
Date d'inscription
vendredi 9 décembre 2011
Statut
Membre
Dernière intervention
7 février 2016
2
Hummm en fait je viens de coder ceci :

#include <iostream>
#include <ctime>
#include <cstdlib>
#include <conio.h>
#include <vector>

using namespace std;

int main()
{
srand(time(0));
int rejouer=1;
int randMax=5;
while (rejouer==1)
{
vector<int> tableau;
int parties=0;
int numeroHasard=0;
for (int j=0; j<randMax; j++)
{
if (parties==0)
{
numeroHasard = ((rand() % randMax) +1);
tableau.push_back(numeroHasard);
parties+=1;
}
else
{
numeroHasard = ((rand() % randMax) +1);
for (int i=0; i<randMax; i++)
{
while (numeroHasard==tableau[i])
{
numeroHasard = ((rand() % randMax) +1);
}
}
tableau.push_back(numeroHasard);
}
}
for (int i=0; i<randMax; i++)
{
cout << "tableau[" << i << "] : " << tableau[i] << "." << endl;
}
getch();
system("cls");
}
return 0;
}



Pourquoi cela ne fonctionne pas vraiment ?

Merci d'avance :)

Dites-le moi si vous voulez des commentaires et j'éditerai :)
Messages postés
493
Date d'inscription
vendredi 9 décembre 2011
Statut
Membre
Dernière intervention
7 février 2016
2
Bonsoir,
premièrement, je vous remercie, tous, pour votre aide et vos conseils.
Avec une combinaison de vos réponses, j'ai réussi à résoudre mon problème.
@cptpingu - En effet, je ne tire pas de mot avec cela, c'est en fait un mini-programme de test pour que cette partie de code soit fonctionnelle pour qu'ensuite je l'implante dans le programme complet.

P.S. Désolé pour le délai, je consacre beaucoup de temps à mes études.
Messages postés
14796
Date d'inscription
vendredi 14 mars 2003
Statut
Modérateur
Dernière intervention
1 juin 2021
155
2 solutions possibles :
1) Si numéro déjà présent, tu avances de 1 et tu revérifie, si tu es à la fin, tu repars au début, comma ça, pas besoin de tirer au hasard tout le temps.
2) Tu fais une liste des lignes possibles, puis tu tires dedans, et retires le numéro récupéré.
Messages postés
493
Date d'inscription
vendredi 9 décembre 2011
Statut
Membre
Dernière intervention
7 février 2016
2
Woah, ce fut rapide ;)

Pour le 2), j'y ai pensé, mais je veux apprendre, et ce n'est pas une option pour cela ^.^

Pour le 1), vous voulez dire que si le chiffre s'y trouve, je fais "+1", je teste s'il s'y trouve, si oui je fais encore "+1", et etc ?
Messages postés
14796
Date d'inscription
vendredi 14 mars 2003
Statut
Modérateur
Dernière intervention
1 juin 2021
155
Tu as compris pour le 1)
Messages postés
14796
Date d'inscription
vendredi 14 mars 2003
Statut
Modérateur
Dernière intervention
1 juin 2021
155
Je bloque sur quelques lignes, notament :
int rejouer(1);
C'est sensé faire quoi ?
ça ne ressemble pas à du C/C++/C#.
Messages postés
493
Date d'inscription
vendredi 9 décembre 2011
Statut
Membre
Dernière intervention
7 février 2016
2
He bien, j'initialise en int la variable "rejouer" avec la valeur 1... int rejouer=1; ferait la même chose, serait-ce mieux que j'adopte cette syntaxe ?
Je me sert de cela pour que le programme reparte automatiquement pour ne pas a avoir à le redémarrer pour avoir une nouvelle combinaison de chiffres.

P.S. C'est du C++, je suis le tutoriel du sdz (openClassroom).
Messages postés
14796
Date d'inscription
vendredi 14 mars 2003
Statut
Modérateur
Dernière intervention
1 juin 2021
155
Il me semble que la syntaxe
int rejouer=1;
est plus commune quand même.
Messages postés
493
Date d'inscription
vendredi 9 décembre 2011
Statut
Membre
Dernière intervention
7 février 2016
2
D'accord, je modifie (ne pas oublier que je suis que débutant et que j'apprends avec le tutoriel du SDZ).
Messages postés
14796
Date d'inscription
vendredi 14 mars 2003
Statut
Modérateur
Dernière intervention
1 juin 2021
155
Dans ton :
while (numeroHasard==tableau[i])
Il faut le remplacer par un if et mettre un while englobant ton for afin de refaire le contrôle sur tout le tableau tant que tu trouve une collision.
Il te faudra bien sûr une variable pour dire si tu as trouvé une collision ou pas.
Messages postés
493
Date d'inscription
vendredi 9 décembre 2011
Statut
Membre
Dernière intervention
7 février 2016
2
J'ai fais ceci, mais cela ne fonctionne pas :
#include <iostream>
#include <ctime>
#include <cstdlib>
#include <conio.h>
#include <vector>

using namespace std;

int main()
{
srand(time(0));
int rejouer=1;
int randMax=5;
while (rejouer==1)
{
vector<int> tableau;
int parties=0;
int numeroHasard=0;
int collision=1;
for (int j=0; j<randMax; j++)
{
if (parties==0)
{
numeroHasard = ((rand() % randMax) +1);
tableau.push_back(numeroHasard);
parties+=1;
}
else
{
numeroHasard = ((rand() % randMax) +1);
while (collision>=1)
{
for (int i=0; i<randMax; i++)
{
if (numeroHasard==tableau[i])
{
collision+=1;
for (int i=0; i<randMax; i++)
{
numeroHasard = ((rand() % randMax) +1);
}
}
else
collision=0;
}
}

tableau.push_back(numeroHasard);
}
}
for (int i=0; i<randMax; i++)
{
cout << "tableau[" << i << "] : " << tableau[i] << "." << endl;
}
getch();
system("cls");
}
return 0;
}

Pourquoi ?
Messages postés
14796
Date d'inscription
vendredi 14 mars 2003
Statut
Modérateur
Dernière intervention
1 juin 2021
155
Il serait bien de dire ce qui ne fonctionne pas, car dire "ça ne fonctionne pas" n'aide pas beaucoup.

Mets
collision=0;
avant le for.

Penses aussi à regarder le mot clé "do", ce serait plus adapté à ton usage qu'un while dans ce code.
Messages postés
3839
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
15 avril 2021
121
Bonjour.

Si tu me précises un peu mieux ce que tu cherches à réaliser, je devrais être en mesure de te corriger ton code. Tu dis que tu veux faire deviner des mots mélangés mais ton code actuel ne le reflète pas (tu stockes des nombres aléatoires, veux-tu faire deviner des nombres ?)

Pour gérer le fait de ne pas redemander toujours les mêmes mots, c'est assez simple:
- Tu stockes N mots dans un tableau.
- Tu mélanges le tableau aléatoirement (fonction std::random_shuffle).
- Tu fais deviner le mot 1, puis 2 puis 3, etc... jusqu'à arriver à la fin.
- Une fois arrivé à la fin, tu remélanges le tableau via std::random_shuffle.

Une autre solution, est de prendre un mot au hasard dans le tableau, et de l'échanger avec la dernière position du tableau.
Puis le prochain mot pris le sera entre 0 et position - 1. Tu échanges à nouveau avec la position - 1. Le prochain mot sera pris entre 0 et position - 2. Etc...

La première solution est bien évidemment plus simple pour le même résultat.

Plusieurs petits soucis techniques:
- Évite les using namespace (erreur classique), voir: http://0217021.free.fr/portfolio/axel.berardino/articles/bon-usage-using-namespace
- Si tu fais du C++11, alors tu peux utiliser un vrai générateur aléatoire, comme un std::mersenne_twister (d'ailleurs si tu utilises std::shuffle au lieu de std::random_shuffle, plus besoin de rand() qui est un reliquat du C). Bien sur, si tu ne souhaites pas ou tu ne peux pas utiliser du C++11, reste sur du C++ classique (C++03 par défaut).
- Au lieu de "int", utlise des "bool" pour du vrai/faux.
- On peut écrire: "parties += 1" en "++parties".
- Pense à découper ton code en petites fonctions, plutôt que d'avoir une grosse fonction monolithique.

Je te propose un squelette propre d'application à compléter:
#include <iostream>
#include <vector>
#include <algorithm>
#include <fstream>
#include <cstdlib>

// Charge les mots à partir d'un fichier ici
// Retourne si le dictionnaire a été correctement chargé (fichier trouvé, fichier correctement formé)
bool load(const std::string& filename, std::vector<std::string>& words)
{
  std::ifstream file(filename.c_str());
  if (!file)
    return false;

  // À toi de jouer.

  return true;
}

// Joue une partie, sur un mot.
void play(const std::string& word)
{
  // Ici fait deviner le mot "word"
}

int main()
{
  srand(time(0));
  const std::string filename = "dico.txt";

  std::vector<std::string> words;
  if (!load(filename, words))
  {
    std::cerr << "Can't load dictionnary: " << filename << std::endl;
    return 1;
  }

  bool rejouer = true;
  int max = words.size();
  int parties = max; // On se met en position: tous les mots ont été devinés.
  while (rejouer)
  {
    // Si on a fait deviner tous les mots.
    if (parties == max)
    {
      parties = 0;
      // Mélange les mots au sein du tableau.
      std::random_shuffle(words.begin(), words.end());
    }

    play(words[parties]);
    ++parties;
    std::cout << "Rejouer ? [1/0]: ";
    std::cin >> rejouer;
  }

  //system("pause"); // Pour Windows

  return 0;
}


__________________________________________________________________________________________________

Améliorez votre expérience CodeS-SourceS avec ce plugin:
http://codes-sources.commentcamarche.net/forum/affich-10000111-plugin-better-cs-2#cptpingu-signature