Signaler

Vecteur non sauvegardé [Résolu]

Posez votre question Juuli 25Messages postés vendredi 3 février 2012Date d'inscription 30 avril 2017 Dernière intervention - Dernière réponse le 9 avril 2017 à 15:42 par Juuli
Bonsoir,
J'essaie de faire une fonction qui distribue aléatoirement des cartes à des joueurs.
Pour l'instant, j'ai:
//carte.h
class Carte {
private:
  int numeroCarte;
  int appartenance;
public:
  // Avec les get/set qui vont avec
};

//mainJoueur.h
class Main {
private:
  vector<Carte*> mainCarte;
  // Un ami m'a dit de mettre Carte* car on me demande un vecteur de lien sur Carte
public:
  // Avec les get/set qui vont avec
};

//manche.h
class Manche {
private:
  int nombreJoueur;
  Carte tabCarte[6]; // Numérotées de 1 à 6
public:
  // Avec les get/set qui vont avec
};

Je n'ai aucun soucis avec les include.

Ce que j'aimerais faire: quand je tire un nombre aléatoire dans tabCarte, je me retrouve avec une carte dont je set l'appartenance au joueur qui l'a tirée.
Ensuite, je set la main du joueur avec cette nouvelle carte.

Mon problème: en ajoutant une carte avec set puis en la récupérant avec get, le numéro de ma carte n'est pas sauvegardé.
Il est bien enregistré entre les deux mais après le get, il redevient 0.
(La fonction distribuer() en elle-même fait ce que j'espère)

Voici ma fonction:
//manche.cpp
void Manche::distribuer () {
  Main tmp;
  int aleatoire, nbCarte;

  for(int i=1; i<=nombreJoueur; ++i) {
    nbCarte = 0;
    while(nbCarte!=3) { // Je veux distribuer 3 cartes
      aleatoire=rand()%6+1;
      if(tabCarte[aleatoire].getAppartenance()==0) { // Si elle n'est à personne
        tabCarte[aleatoire].setAppartenance(i);
        tmp.setMainCarte(i-1,tabCarte[aleatoire]);
        nbCarte++;
      }
    }
  }
}

Et voici les getMainCarte() et setMaincarte():
//mainJoueur.cpp
vector<Carte*> Main::getMainCarte () {
  return mainCarte;
}

void Main::setMainCarte (const int numJ, const Carte c) {
  *mainCarte[numJ]=c;
}

/* Constructeur pour ce setMainCarte */
Main::Main () {
  Carte c;
  for(int i=0; i<3; ++i)
    mainCarte.push_back(&c);
}
/* FIN */

/* Sinon, une variante (plus besoin du constructeur) */
void Main::setMainCarte (Carte c) {
  mainCarte.push_back(&c);
}


Mes tests:
1. Dans ma fonction distribuer(), je fais un
main.setMainCarte(0,tabCarte[1]);
// tabCarte[6] correctement initialisé
// tabCarte[i].getNumeroCarte() renvoie i

2. Dans ce setMainCarte() de mainJoueur.cpp, je fais un
cout << "Set: " << mainCarte[numJ]->getNumeroCarte();
// Affiche 1
cout << "Get: " <<getMainCarte()[numJ]->getNumeroCarte();
// Affiche 0

Donc ce serait un problème au niveau du get. On dirait qu'il n'est pas sauvegardé. Comment faudrait-il faire ?

Sur internet, j'ai vu:
vector<int>& getFoo ()

Mais ça ne change rien.

Un vector<Carte*> est-il vraiment nécessaire pour la consigne ou puis-je faire un vector<Carte> tout simple ?

Voilà, j'espère que vous pourriez m'aider.
Je vous remercie d'avance.
Juuli

PS: Je re-précise que tout le reste marche, sauf cette "sauvegarde"
Utile
+0
plus moins
Vu que c'est en c++ je pense que tu peux faire un passage par référence non.

Je ne sais pas si cela marche et je ne saurais pas où le mettre dans le code.

C'est juste une petite idée.
Donnez votre avis
Utile
+0
plus moins
Bonjour,

Il y a 'quelques' petits soucis dans ce code.
  • On n'utilise pas de getter/setter en C++. Une donnée est librement accessible ou est privée.
  • La structure globale est 'curieuse', il est plus facile de poser qu'un Joueur possède une Main de N Cartes, que de considérer que c'est la Carte qui sait quel est son propriétaire. Ici les Mains ne sont pas associées aux Joueurs.
  • ligne 9 de distributer.cpp, aleatoire varie de 1 à 6 et on l'utilise comme index dans un tableau de 6 éléments qui exige des index de 0 à 5.
  • Utilisation de pointeurs. Un pointeur doit pointer quelque part, on s'en sert en écrivant à l'endroit pointé. Ton code fait pointer les pointeurs sur une variable locale du constructeur, qui disparaît donc les pointeurs pointent n'importe où. => Apprendre les pointeurs, ne s'en servir qu'une fois compris.
  • L'exemple vu sur internet d'utilisation de référence est une piste. Il faut cependant apprendre les références auparavant.
  • dans distribuer, les cartes sont mises dans une Main appelée judicieusement tmp. Et en effet, tmp disparaît dès la fin de la fonction; alors à quoi cela sert-il?


Alors, commencer par utiliser un vector<Carte>, les cartes seront ainsi vraiment stockées. Tu utilises toujours des passages d'informations par copie (par exemple setMainCarte( Carte c ) va recevoir une Carte qui est la copie de la carte qu'on lui a passé), cela peut fonctionner ici mais risque d'amener à des bugs ultérieurs.
Donnez votre avis
Utile
+0
plus moins
Bonjour,
Tout d'abord, merci de votre réponse à tous les deux.

@Dalfab
○ J'ignorais que les get/set n'étaient pas utilisés en C++ :o
Pourtant, les enseignants nous disent qu'il faut en mettre. Du moins, ils en mettent dans leurs exemples et dans un projet précédant qui était plus guidé que celui-ci, nous étions obligés d'en mettre.
De ce que j'ai compris du cours, nos données membres doivent être privées, d'où le get/set pour pouvoir les toucher dans d'autres fichiers.

○ En effet, j'ai essayé de résumer un peu les fichiers que j'avais en montrant les plus concernés. J'ai bien un joueur.cpp qui a seulement un pseudo et une main.
L'appartenance avait été faite par un collègue. Il me semble que c'était pour pouvoir récupérer plus facilement le numéro du joueur pour le déroulement du jeu.

○ J'ai commencé à 1 car dans notre jeu la carte 0 n'existe pas.
Voici la fonction qui permet d'attribuer les numéros du tableau de carte:
//manche.cpp
void Manche::attribuerNumero () {
  for(int i = 1; i <= 104; i++) { // Pour les tests, j'ai réduit à 6 cartes
    tabCarte[i].setNumeroCarte(i);
  }
}

Je vais corriger cette erreur de ce pas ;)
// Les tabCarte des lignes 10 , 11 et 12 deviennent:
tabCarte[aleatoire-1]


○ Donc il faudrait laisser le constructeur vide et préférer le setMainCarte() faisant un push_back (si on garde les get/set) ?

(et @The Gaming Zone)
○ J'ai cherché un exemple sur internet (http://cermics.enpc.fr/polys/info1/main/node33.html)
Je comprends l'idée donc il faudrait par exemple faire:
//mainJoueur.cpp
void Main::exemple (vector<Carte*> & m) {
  m = mainCarte;
}

?
Mais je ne pense pas que ce soit ce que je veuille.

○ tmp stocke juste une main et ensuite, je peux l'attribuer à un joueur puis on recommence pour le prochain joueur. La fonction que j'aimerais faire:
//manche.cpp
void Manche::distribuer () {
  Main tmp;
  int aleatoire, nbCarte;

  for(int i=1; i<=nombreJoueur; ++i) {
    nbCarte = 0;
    while(nbCarte!=3) { // Je veux distribuer 3 cartes
      aleatoire=rand()%6+1;
      if(tabCarte[aleatoire-1].getAppartenance()==0) { // Si elle n'est à personne
        tabCarte[aleatoire-1].setAppartenance(i);
        tmp.setMainCarte(i-1,tabCarte[aleatoire-1]);
        nbCarte++;
      } // fin if
    } // fin while
    tmp.trierMain(tmp);
    tabJoueur[i-1]->setJoueurMain(tmp);
  } // fin for
}

//manche.h
class Manche {
private:
  int nombreJoueur;
  vector<Joueur*> tabJoueur;
  Carte tabCarte[6]; // Numérotées de 1 à 6
public:
  // Avec les get/set qui vont avec
};



La première version de notre code était avec des vector<Carte> tout simple (ça marchait). Mais quand on l'a montré à notre professeur, il nous a dit qu'un vecteur de lien sur Carte serait plus judicieux.

Mon camarade m'a dit que ça s'écrivait ainsi: vector<Carte*>.
Je pose la question de l'* car comme tu as pu le voir, j'ai d'autres vector qui poseront sans doute problème dès que j'aurais fini de régler distribuer().

Avant, distribuer() ne prenait pas en compte le tabCarte[104] donc il y avait pas mal de problèmes avec Valgrind.

Liste des fichiers concernés:
manche.cpp/h, mainJoueur.cpp/h, joueur.cpp/h, carte.cpp/h

PS: C'est la première fois que je manipule vector et stack
Donnez votre avis
Utile
+0
plus moins
J'ignorais que les get/set n'étaient pas utilisés en C++ :o
Pourtant, les enseignants nous disent qu'il faut en mettre. Du moins, ils en mettent dans leurs exemples et dans un projet précédant qui était plus guidé que celui-ci, nous étions obligés d'en mettre.
De ce que j'ai compris du cours, nos données membres doivent être privées, d'où le get/set pour pouvoir les toucher dans d'autres fichiers.

Un objet n'est pas un espace de stockage, c'est un service. Toutes les données doivent être privées donc aucun intérêt à avoir des get/set. Ça a eu existé, mais cela fait 20 ans qu'on les enlève.

J'ai commencé à 1 car dans notre jeu la carte 0 n'existe pas.
Je vais corriger cette erreur de ce pas ;)
// Les tabCarte des lignes 10 , 11 et 12 deviennent:
tabCarte[aleatoire-1]

Ok

Donc il faudrait laisser le constructeur vide et préférer le setMainCarte() faisant un push_back (si on garde les get/set) ?
Oui, mais lui n'est pas un setter (il interprète et ne remplace pas bêtement le vecteur, ce que ferait un setter), et en lecture il faudrait éviter un getter retournant le vecteur (un utilisateur de Main n'a pas à connaître la structure interne de Main)

tmp stocke juste une main et ensuite, je peux l'attribuer à un joueur puis on recommence pour le prochain joueur.
Ok, ici il y a passage par copie, c'est ce qu'il faut

La première version de notre code était avec des vector<Carte> tout simple (ça marchait). Mais quand on l'a montré à notre professeur, il nous a dit qu'un vecteur de lien sur Carte serait plus judicieux.
Pourquoi pas, mais s'il y a pointeur, il faut qu'il pointe sur une zone fixe (ça serait vers un élément de la tabCarte[]).

Mon camarade m'a dit que ça s'écrivait ainsi: vector<Carte*>.
Je pose la question de l'* car comme tu as pu le voir, j'ai d'autres vector qui poseront sans doute problème dès que j'aurais fini de régler distribuer().

D'où la nécessité de bien comprendre ce qu'est un pointeur.

La fonction avec
vector<Carte*>
serait :
// on reçoit une référence(&) sur la Carte c, pas une copie
void Main::setMainCarte( int numJ , Carte &c ) {
  // prendre l'adresse d'une référence c'est pointer sur l'objet transmis, qui ne devra pas disparaître avant la fin de la partie.
  mainCarte.push_back( &c );
}
Juuli 25Messages postés vendredi 3 février 2012Date d'inscription 30 avril 2017 Dernière intervention - 9 avril 2017 à 15:42
Bonjour @Dalfab,

J'ai lu le cours sur les pointeurs. Il est vrai que je sais en théorie comment ça marche mais j'ai encore du mal à savoir quand les utiliser.
Si on ne me met pas de contrainte, je n'en n'aurais jamais mis.

Du coup, j'ai mis la seconde version du set que je renommerai plus tard.
Et les cartes tirées au hasard sont bien conservées.

Je me demande si je fusionnerais joueur.cpp et mainJoueur.cpp pour attribuer directement la main au joueur au lieu de la recopier dans mainJoueur puis l'attribuer à joueur à partir de mainJoueur...

En tout cas, je te remercie beaucoup de ton aide.
Je te souhaite une bonne après-midi,
Juuli

Et merci encore ! :D
Répondre
Donnez votre avis

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.

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

Vous n'êtes pas encore membre ?

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