multi_array qui produit un SIGABRT
Salut à vous tous
Je suis en train de mijoter sur un générateur de labyrinthe tout simple.
Le principe de mon algo est simple: Je commence en 0,0 et je me déplace dans une des cases adjacente disponible.
Une fois bougé, je marque la case comme «occupée» et je continue à me déplacer dans une de nouvelles cases adjacente libre (l'algo ne repasse jamais 2x au même endroit).
S'il n'y a plus de case adjacente disponible, je recule de 1 et je regarde s'il y a une case disponible. Si oui, j'avance, si non, je continue à reculer.
Une fois revenu au point de départ, le labyrinthe est généré.
Comme vous le voyez, le processus est très simple, ce n'est pas quelque chose de très élaboré (on verra ça plus tard). Je veux d'abord que ça marche.
Pour stocker mon labyrinthe, j'utilise un multi_array de Boost.
Ce multi_array fait [largeur][hauteur][5] et est de type bool
Dans chaque case, j'ai donc 5 booléens qui valent
0)Visité (facultatif mais j'aime bien)
1)HAUT
2)BAS
3)GAUCHE
4)DROITE
Chaque case étant à «false» si la «porte» de la cellule est fermée et à «true» si elle est ouverte.
Bon… je viens de vous baratiner pendant un p'tit tas de lignes et je ne vous ai toujours pas dit ce qui coinçait, mais j'y viens.
Ce générateur de labyrinthe a la fâcheuse manie de provoque une «SIGABRT» lorsqu'il arrive dans une case touchant un bord du tableau.
Vous allez dire «bah, il sort des limites, c'est tout»… ben non… J'ai vérifié et contre-vérifié tout le code 5 fois et je n'arrive toujours pas à comprendre pourquoi il génère un SIGABRT…
Mais trève de bavardage, voici mon code:
Le .h d'abord
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| #ifndef GENERATOR_H
#define GENERATOR_H
#include <boost/multi_array.hpp>
#include <list>
#include <map>
#include <iostream>
#include <cstdlib>
class Generator
{
public:
enum class direction{HAUT, BAS, GAUCHE, DROITE};
Generator();
virtual ~Generator();
protected:
private:
//Déclarations du type du MultiArray
typedef boost::multi_array<bool, 3> multiArray;
void genereChemin();
void resetDirections();
void findBorders();
void findVisited();
//Création des deux multiArray
multiArray labyrinthe, labyrintheDos;
std::list<std::pair<int, int> > chemin;
std::map<Generator::direction, bool> directions;
std::pair<int, int> position;
};
#endif // GENERATOR_H |
Puis le .cpp
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
| #include "Generator.h"
Generator::Generator(){
//Variables de taille, pour le moment aléatoires
int const longueur(5), largeur(5);
//Initialisation de rand
srand(time(NULL));
labyrinthe.resize(boost::extents[longueur][largeur][5]);
labyrintheDos.resize(boost::extents[longueur][largeur][5]);
for(int i=0; i<longueur; ++i){
for(int j=0; j<largeur; ++j){
for(int k=0; k<5; ++k){
labyrinthe[i][j][k] = false;
labyrintheDos[i][j][k] = false;
}
}
}
int larg = labyrinthe
this->resetDirections();
this->genereChemin();
}
Generator::~Generator(){
//dtor
}
void Generator::genereChemin(){
//On part toujours du coin supérieur gauche
chemin.push_back(std::make_pair(0, 0));
position = std::make_pair(0, 0);
labyrinthe[0][0][0] = true; //La première case est visitée
//Tant qu'on est pas revenu au début, on poursuit la génération
while(!chemin.empty()){
//Le principe est simple, on avance toujours et quand on ne peut plus, on recule
//On remet le bordures à zéro
this->resetDirections();
//Délimitation des bordures
this->findBorders();
//Élimination des cases visitées adjacentes
//HINT : Accepter une case visitée dans 20% des cas!
this->findVisited();
bool avancer = false;
std::map<Generator::direction, bool>::iterator it;
while(!avancer){
//On fait des tours de boucle tant qu'on ne peut pas avancer
for(it = directions.begin(); it != directions.end(); ++it){
if(directions[it->first]){
avancer = true;
break;
}//Fin IF
}//Fin FOR
if(!avancer){
//Si on est ici, c'est qu'il est impossible d'avancer
this->resetDirections();
//On vérifie qu'on est pas revenu au début
if(chemin.empty()){
return;
}
chemin.pop_back();
position = chemin.back();
//On recherche les bordures
this->findBorders();
//Et les cases visitées
this->findVisited();
}
}//Fin WHILE
//S'il est possible d'avancer, on tire une direction au hasard
Generator::direction wayToGo;
bool ok = false;
//Tant que la direction n'est pas OK, on retire
while(!ok){
wayToGo = static_cast<Generator::direction>(rand() % (static_cast<int>(Generator::direction::DROITE)+1));
if(directions[wayToGo]){
//Si la direction est bonne, on la garde
ok = true;
}
}
//Si on est ici, c'est qu'on a une direction donc, on bouge!
switch(wayToGo){
case Generator::direction::HAUT:
//On change la position
position = std::make_pair(position.first, position.second-1);
chemin.push_back(position);
//Et on visite les cases
labyrinthe[position.first][position.second][0] = true;
labyrinthe[position.first][position.second][2] = true; //BAS (vu qu'on monte)
labyrinthe[position.first][position.second-1][1] = true; //HAUT
break;
case Generator::direction::BAS:
position = std::make_pair(position.first, position.second+1);
chemin.push_back(position);
//Visite des cases
labyrinthe[position.first][position.second][0] = true;
labyrinthe[position.first][position.second][1] = true; //HAUT
labyrinthe[position.first][position.second+1][2] = true; //BAS
break;
case Generator::direction::GAUCHE:
position = std::make_pair(position.first-1, position.second);
chemin.push_back(position);
//Visite des cases
labyrinthe[position.first][position.second][0] = true;
labyrinthe[position.first][position.second][4] = true; //DROITE
labyrinthe[position.first-1][position.second][3] = true; //GAUCHE
break;
case Generator::direction::DROITE:
position = std::make_pair(position.first+1, position.second);
chemin.push_back(position);
//Visite des cases
labyrinthe[position.first][position.second][0] = true;
labyrinthe[position.first][position.second][3] = true; //GAUCHE
labyrinthe[position.first+1][position.second][4] = true; //DROITE
break;
default:
std::cerr << "ERREUR fatale" << std::endl << "La direction choisie est invalide" << std::endl;
exit(EXIT_FAILURE);
break;
}
}
return;
}
//Remet toutes les directions à TRUE
void Generator::resetDirections(){
directions[direction::HAUT] = true;
directions[direction::BAS] = true;
directions[direction::GAUCHE] = true;
directions[direction::DROITE] = true;
return;
}
//Trouve les bordures du labyrinche
void Generator::findBorders(){
if(position.second == 0)
directions[direction::HAUT] = false;
if(position.second == 4)
directions[direction::BAS] = false;
if(position.first == 0)
directions[direction::GAUCHE] = false;
if(position.first == 4)
directions[direction::DROITE] = false;
return;
}
//Trouve les cases visitées aux alentours de la case actuelle
void Generator::findVisited(){
std::map<Generator::direction, bool>::iterator it;
for(it = directions.begin(); it != directions.end(); ++it){
switch(it->first){
case direction::HAUT:
if(directions[it->first]){
if(labyrinthe[position.first][position.second-1][0]){
directions[direction::HAUT] = false;
}
}
break;
case direction::BAS:
if(directions[it->first]){
if(labyrinthe[position.first][position.second+1][0]){
directions[direction::BAS] = false;
}
}
break;
case direction::GAUCHE:
if(directions[it->first]){
if(labyrinthe[position.first-1][position.second][0]){
directions[direction::GAUCHE] = false;
}
}
break;
case direction::DROITE:
if(directions[it->first]){
if(labyrinthe[position.first+1][position.second][0]){
directions[direction::DROITE] = false;
}
}
break;
default:
std::cout << "ERREUR*FATALE" << std::endl << "Exception de direction trouvée" << std::endl;
exit(EXIT_FAILURE);
} //Fin du SWITCH
}//Fin du FOR
} |
Si vous voulez tester le code, le plus simple est de mettre 4 breakpoints. Un à chaque case du «switch(wayToGo)». (lignes 93, 101, 109, 117)
Le problème survient généralement à cette ligne:
Code:
labyrinthe[position.first][position.second][0] = true;
Et je vous avoue que je n'ai vraiment aucune idée d'où peut bien provenir ce fichu SIGABRT.
Pour les tests, le labyrinthe fait 5x5 donc en moins de 10 mouvements, le programme plante.
Et pour info, il est nécessaire d'activer la norme «C++11» dans le compilateur.
Un immense merci à tous ceux qui pourront m'aider.