- 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8
- 8 X X X X X 0 X X X X X 0 X X X X 0 X X X 0 X X X X X X X 0 0 X X X X X X X X 8
- 8 X 0 0 X 0 0 X 0 X 0 0 X X 0 0 X X X 0 X 0 X 0 0 0 0 X 0 X X X 0 0 0 0 0 X 0 8
- 8 X X 0 X X X X 0 X 0 0 X 0 X X X 0 X 0 X 0 0 X X X 0 X X X 0 X 0 X X X X X X 8
- 8 0 X X 0 0 0 X 0 X X X X 0 X 0 0 0 X 0 X X 0 X 0 X X 0 X 0 X X 0 X 0 X 0 X 0 8
- 8 X 0 X 0 X X 0 X 0 0 0 0 X 0 X X X X 0 0 X 0 X X 0 X X 0 X X 0 X X 0 X 0 X X 8
- 8 X 0 X X 0 X X X X X X 0 X 0 X 0 0 0 X 0 X X 0 X X 0 X 0 0 0 X X 0 X 0 X X 0 8
- 8 X 0 X 0 X X 0 0 X 0 X X X 0 X 0 X X X 0 0 X 0 0 X 0 X X X X X 0 X X X X 0 X 8
- 8 X 0 X X 0 X X X 0 X X 0 0 X X 0 0 0 X X 0 X X X X X 0 0 0 0 0 X 0 X 0 0 X X 8
- 8 X 0 0 X X 0 0 X X 0 X 0 X X 0 X X X 0 X X X 0 0 0 0 X X X X 0 X X X X 0 0 X 8
- 8 X X 0 0 X X X 0 0 0 X 0 X 0 X X 0 X 0 0 X 0 X X X X X 0 0 X X 0 0 0 X X X X 8
- 8 0 X X X X 0 X X X X X 0 X 0 0 X 0 X X X 0 X X 0 X 0 0 X X X 0 X X X 0 0 X 0 8
- 8 X 0 0 0 0 X 0 X 0 0 X 0 X X X X X 0 0 X 0 X 0 0 0 X X X 0 0 X X 0 X X 0 X X 8
- 8 X X X X X X X 0 X X X 0 0 0 0 0 X X 0 X X X X 0 X X 0 0 X 0 X 0 X 0 X 0 0 0 8
- 8 0 X 0 0 0 0 X 0 X 0 0 X X X X X 0 0 X 0 0 X 0 0 X 0 X X X 0 X 0 X 0 X X X X 8
- 8 X X X X X 0 X X 0 0 X X 0 0 0 X 0 X X X X 0 X X X 0 X 0 X X X 0 X 0 X 0 0 X 8
- 8 X 0 0 0 X X 0 X X X X 0 X X X X 0 X 0 0 X X X 0 0 0 X X 0 0 0 X X X 0 0 0 X 8
- 8 X 0 X X 0 X X 0 0 0 0 X X 0 X 0 X X X 0 0 X 0 X X X 0 X 0 X X 0 0 X X 0 X X 8
- 8 X 0 X 0 X 0 X X X X 0 0 X X 0 X X 0 X X X 0 X X 0 X X X 0 0 X X X 0 X 0 X 0 8
- 8 X 0 X X X 0 0 0 0 X X X 0 X X X 0 X X 0 X 0 X 0 X 0 0 0 X X X 0 X 0 X 0 X X 8
- 8 X 0 0 X 0 X X X 0 X 0 X 0 0 0 0 0 0 0 X 0 0 X 0 X X X 0 X 0 X 0 X X X 0 X 0 8
- 8 X X 0 X X X 0 X X 0 X X X X X X 0 X X X X X X 0 X 0 X X X X 0 X 0 0 X 0 X 0 8
- 8 0 X X 0 X 0 X 0 X X 0 0 0 0 0 X 0 X 0 0 0 X 0 0 X X 0 0 0 X 0 X X X X 0 X X 8
- 8 X 0 X 0 X X X X 0 X X X X X 0 X X X 0 X X 0 X X X 0 0 X X X 0 X 0 X 0 X 0 X 8
- 8 X 0 X X 0 X 0 X X 0 0 0 0 X X 0 0 0 X 0 X X X 0 0 X X X 0 0 X X 0 0 X X X X 8
- 8 X X 0 X X 0 X X 0 X X X X 0 X X X X X X 0 X 0 0 X X 0 0 X X X 0 X 0 X 0 0 X 8
- 8 X 0 X 0 X X 0 0 X X 0 0 X 0 0 X 0 X 0 X X 0 X X X 0 X 0 X 0 X X X 0 X X X 0 8
- 8 X 0 X X 0 X X X X 0 X 0 X X X 0 0 X X 0 X X X 0 0 X X 0 X 0 X 0 0 X 0 0 X 0 8
- 8 X X X 0 X 0 0 0 0 X X X 0 0 X X X 0 X X 0 X 0 X X 0 X 0 X X 0 X X X X 0 X X 8
- 8 0 X 0 X X X X X X 0 0 X X X 0 0 X X 0 X 0 0 X 0 X X X X 0 X 0 X 0 0 X 0 0 X 8
- 8 X X X X 0 X 0 0 X X X 0 X 0 X X 0 X 0 X X X X 0 X 0 0 X 0 X 0 X 0 X X X 0 X 8
- 8 X 0 X 0 0 X X 0 0 0 X X X 0 X 0 X X 0 X 0 0 X 0 X 0 X X 0 X 0 X X 0 0 X X X 8
- 8 X 0 0 X X X 0 X X X 0 X 0 X X X 0 X 0 0 0 X X 0 X X 0 X X X X 0 X 0 X X 0 X 8
- 8 X X X 0 X 0 X X 0 X 0 X 0 X 0 X X X X X X X 0 X 0 X X 0 X 0 X 0 X 0 0 X X 0 8
- 8 X 0 X 0 X 0 X 0 0 X X 0 X X X 0 0 0 0 X 0 X X X X 0 X 0 0 X 0 0 X X X 0 X X 8
- 8 X 0 X 0 0 0 X X X 0 X X X 0 X 0 X X 0 0 0 X 0 0 X X 0 X X X X X 0 0 X X 0 X 8
- 8 X 0 X X X X 0 X 0 X 0 0 X 0 X X X 0 X X X 0 X X X 0 X X 0 X 0 X X X 0 X X 0 8
- 8 X 0 0 0 0 X X X X X 0 X 0 X 0 0 0 X X 0 X X 0 0 0 X X 0 X 0 X 0 0 X 0 0 X X 8
- 8 X X X X X 0 X 0 0 X X X 0 X X X X X 0 0 0 X X X X X 0 X X X X X X X X X X 0 8
- 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8
Generator de labirint
Am fost forțat rugat de către DarkByte să implementez un algoritm care să genereze un labirint perfect. O regulă de bază ar fi că din orice punct al labirintului poti să vizitezi orice alt punct(vorbim despre puncte care aparțin "drumului" ). Un site unde găsiți mai multe informații despre labirinturi pentru pasionați ar fi acesta.
Ce se întâmplă în spate?
Algoritmul este un DFS ( Deep-First Search ). Metoda mea bordează matricea cu cifra 8 pe margini (funcția build_wall). Apoi se generează un punct cu două coordonate random (funcția rand_start). Acel punct (cell) va fi locul de unde începe algoritmul să genereze labirintul. Coordonatele unui punct sunt reținte într-o structură (coordinate). Punctul cell este adăugat la stivă (trail-pentru a reține drumul parcurs).
Din poziția curentă (cell) algoritmul se uită dacă există vreo celulă ocupabilă din jurul poziției curente (funcția posib_nextcell). Dacă există alege una random dacă aceasta este ocupabilă (funcția get_nextcell) și o adaugă la stivă. Desigur, nu e cea mai eficientă metodă (randomul poate să selecteze o celulă neocupabilă de mai multe ori; se poate rezolva problema asta dar altă dată, poate la o versiune 0.2).
Putem observa ideea de DFS. Se alege o singură celulă-vecină(chiar dacă pot exista mai multe celule-vecine) și se continuă. Algoritmul continuă să selecteze puncte ocupabile și le adaugă la stivă. Dacă ajunge într-o poziție din care nu poate să continue se scoate un element din stivă și se uită dacă poate continua din altă poziție anterioară.
Algoritmul se termină când stiva este goală, deci se revine în poziția de unde am început să generăm algoritmul.
Codul:
- #include <queue>
- #include <iostream>
- #include <cstdio>
- #include <stack>
- #include <cstdlib>
- #include <time.h> //optional - depends on operating sistem, i think
- #define WALL_VALUE 8
- using namespace std;
- int lab[500][500]; //the matrix :))
- /*
- A structure to represent a point in a matrix
- */
- struct coordinate
- {
- short int x; // the x coordinate
- short int y; // the y coordinate
- };
- /*
- A function which returns the south coordinates from a given position
- param posit The given position
- */
- coordinate south(coordinate posit)
- {
- coordinate temp;
- temp.x=posit.x-1; //one line -> down
- temp.y=posit.y;
- return temp;
- }
- /*
- A function which returns the north coordinates from a given position
- param posit The given position
- */
- coordinate north(coordinate posit)
- {
- coordinate temp;
- temp.x=posit.x+1; // one line -> up
- temp.y=posit.y;
- return temp;
- }
- /*
- A function which returns the east coordinates from a given position
- param posit The given position
- */
- coordinate east(coordinate posit)
- {
- coordinate temp;
- temp.x=posit.x;
- temp.y=posit.y+1; //one collumn ->right
- return temp;
- }
- /*
- A function which returns the west coordinates from a given position
- param posit The given position
- */
- coordinate west(coordinate posit)
- {
- coordinate temp;
- temp.x=posit.x;
- temp.y=posit.y-1; //one collumn ->left
- return temp;
- }
- /*
- A function which returns true if the cell passed to it is free to be
- occupied. The functions looks around the given cell (south,north,
- east,west) and sums the values within that surounding cells of the matrix.
- The rule is that a free cell can have at most one neighbour.
- The "% WALL_VALUE" is there so we can "eliminate" the exterior wall.
- See the define (up) and the build_wall function.
- param posit The given position
- */
- bool is_empty(coordinate posit)
- {
- if (lab[posit.x][posit.y]==0)
- {
- coordinate sou=south(posit);
- coordinate nor=north(posit);
- coordinate eas= east(posit);
- coordinate wes= west(posit);
- int sum=lab[sou.x][sou.y]+
- lab[nor.x][nor.y]+
- lab[eas.x][eas.y]+
- lab[wes.x][wes.y];
- return (sum % WALL_VALUE) <= 1 ;
- }
- return false;
- }
- /*
- A function which returns true if there are free to be occupied
- cells around a given point(cell). If at least one of the (south,
- north,east,west) cells is free, then the given point(cell) has free
- to be occupied cells around it therefore the function returns true.
- param posit The given position
- */
- bool posib_nextcell(coordinate posit)
- {
- return (is_empty(south(posit)) ||
- is_empty(north(posit)) ||
- is_empty(east(posit) ) ||
- is_empty(west(posit) ) );
- }
- /*
- A function which returns a random coordinate of a free cell
- around a given point(cell).
- param posit The given position
- */
- coordinate get_nextcell(coordinate posit)
- {
- coordinate aux;
- bool ok = false;
- while ( !ok )
- {
- int gen = ( rand() % 4 ) +1;
- switch(gen){
- case 1: aux=south(posit); break;
- case 2: aux=north(posit); break;
- case 3: aux=east(posit); break;
- case 4: aux=west(posit); break;
- }
- if ( is_empty(aux) ) ok=true;
- }
- return aux;
- }
- /*
- A function which builds a wall on the exterior lines and columns
- of the matrix. The function fills the exterior with the number "8".
- param LIN The number of lines that the matrix has
- param COL The number of columns that the matrix has
- */
- void build_wall(int LIN,int COL)
- {
- for (int x=0;x<COL;x++) lab[0][x]=lab[LIN-1][x]=8; //first and last line
- for (int y=0;y<LIN;y++) lab[y][0]=lab[y][COL-1]=8; //first and last column
- }
- /*
- A function which prints the matrix.
- param LIN The number of lines that the matrix has
- param COL The number of columns that the matrix has
- */
- void print(int LIN,int COL)
- {
- for (int y=0;y<LIN;y++)
- {
- for(int x=0;x<COL;x++) cout<<lab[y][x]<<" ";
- cout<<'\n';
- }
- }
- /*
- A function which generates a X and Y coordinate for the starting
- point from which the program will generate the labyrinth.
- param LIN The number of lines that the matrix has
- param COL The number of columns that the matrix has
- */
- coordinate rand_start(int LIN,int COL)
- {
- coordinate aux;
- srand ( time(NULL) );
- aux.x=rand() % LIN; if (aux.x==0) aux.x++;
- aux.y=rand() % COL; if (aux.y==0) aux.y++;
- return aux;
- }
- /*
- The main function
- */
- int main()
- {
- stack <coordinate> trail; //the stack on which the program will "remember" the road
- int LIN=40,COL=40; //the number of lines and the number of columns
- //modify this for different labyrinth sizes
- build_wall(LIN,COL); //builds the wall
- coordinate cell = rand_start(LIN,COL); // generates the first cell coordinates
- trail.push(cell); //pushes the coordinates of the cell in the stack
- lab[cell.x][cell.y]=1; //marks the cell from the matrix as "visited"
- // LEGEND:
- // 8 - permanent wall
- // 0 - wall
- // 1 - road
- /*
- This part repeats until the stack is empty. The algorith is a
- Deep-First Search. The program looks for the fist occupiable
- point next to a given point. It adds it to the stack and so on.
- If it gets to a dead end the program pops some cells from the
- stacks. At every point the algorithm looks for new free cells.
- The program ends when the stack is empty and the labyrinth is generated.
- */
- while(!trail.empty())
- {
- cell=trail.top();
- if (posib_nextcell(cell))
- {
- cell=get_nextcell(cell);
- trail.push(cell);
- lab[cell.x][cell.y]=1;
- }
- else
- {
- trail.pop();
- }
- }
- print(LIN,COL); //prints the generated labyrinth
- return 0;
- }
Performanță și un exemplu:
Nu prea putem să vorbim despre performanță până când nu voi rezolva problema acelui random. Complexitatea algoritmului DFS este de O ( V + M ) , unde V reprezintă numărul de varfuri și M numărul de muchii. Totuși programul rulează ireproșabil sub o secundă pentru matrici de 500x500.
Exemplul următor este un labirint de 40x40. Am înlocuit 1 cu X ca să se vedea mai bine care e drum și care nu.
- 8 -zid permanent (exterior)
- X -drum
- 0 -zid
Thanks for reading!

P.S.: Nu promit, dar probabil că în viitor va exista altă versiune, poate și cu gui.
Welcome to BitCell. Click here to register !
