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

Alain2131 507 Messages postés vendredi 9 décembre 2011Date d'inscription 7 février 2016 Dernière intervention - 1 févr. 2015 à 20:41 - Dernière réponse : Alain2131 507 Messages postés vendredi 9 décembre 2011Date d'inscription 7 février 2016 Dernière intervention
- 1 mars 2015 à 03:04
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.

:)
Afficher la suite 

13 réponses

Répondre au sujet
NHenry 14057 Messages postés vendredi 14 mars 2003Date d'inscriptionModérateurStatut 14 février 2018 Dernière intervention - 1 févr. 2015 à 20:49
0
Utile
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é.
Commenter la réponse de NHenry
Alain2131 507 Messages postés vendredi 9 décembre 2011Date d'inscription 7 février 2016 Dernière intervention - 1 févr. 2015 à 20:56
0
Utile
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 ?
Commenter la réponse de Alain2131
NHenry 14057 Messages postés vendredi 14 mars 2003Date d'inscriptionModérateurStatut 14 février 2018 Dernière intervention - 1 févr. 2015 à 21:07
0
Utile
Tu as compris pour le 1)
Commenter la réponse de NHenry
Alain2131 507 Messages postés vendredi 9 décembre 2011Date d'inscription 7 février 2016 Dernière intervention - Modifié par Alain2131 le 1/02/2015 à 21:27
0
Utile
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 :)
Commenter la réponse de Alain2131
NHenry 14057 Messages postés vendredi 14 mars 2003Date d'inscriptionModérateurStatut 14 février 2018 Dernière intervention - 1 févr. 2015 à 21:18
0
Utile
Je bloque sur quelques lignes, notament :
int rejouer(1);
C'est sensé faire quoi ?
ça ne ressemble pas à du C/C++/C#.
Commenter la réponse de NHenry
Alain2131 507 Messages postés vendredi 9 décembre 2011Date d'inscription 7 février 2016 Dernière intervention - Modifié par Alain2131 le 1/02/2015 à 21:22
0
Utile
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).
Commenter la réponse de Alain2131
NHenry 14057 Messages postés vendredi 14 mars 2003Date d'inscriptionModérateurStatut 14 février 2018 Dernière intervention - 1 févr. 2015 à 21:24
0
Utile
Il me semble que la syntaxe
int rejouer=1;
est plus commune quand même.
Commenter la réponse de NHenry
Alain2131 507 Messages postés vendredi 9 décembre 2011Date d'inscription 7 février 2016 Dernière intervention - 1 févr. 2015 à 21:25
0
Utile
D'accord, je modifie (ne pas oublier que je suis que débutant et que j'apprends avec le tutoriel du SDZ).
Commenter la réponse de Alain2131
NHenry 14057 Messages postés vendredi 14 mars 2003Date d'inscriptionModérateurStatut 14 février 2018 Dernière intervention - 1 févr. 2015 à 21:26
0
Utile
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.
Commenter la réponse de NHenry
Alain2131 507 Messages postés vendredi 9 décembre 2011Date d'inscription 7 février 2016 Dernière intervention - 1 févr. 2015 à 21:58
0
Utile
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 ?
Commenter la réponse de Alain2131
NHenry 14057 Messages postés vendredi 14 mars 2003Date d'inscriptionModérateurStatut 14 février 2018 Dernière intervention - 1 févr. 2015 à 23:17
0
Utile
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.
Commenter la réponse de NHenry
cptpingu 3778 Messages postés dimanche 12 décembre 2004Date d'inscriptionModérateurStatut 15 février 2018 Dernière intervention - Modifié par cptpingu le 2/02/2015 à 11:15
0
Utile
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
Commenter la réponse de cptpingu
Alain2131 507 Messages postés vendredi 9 décembre 2011Date d'inscription 7 février 2016 Dernière intervention - Modifié par Alain2131 le 1/03/2015 à 03:05
0
Utile
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.
Commenter la réponse de Alain2131

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.