596 lines
23 KiB
C
596 lines
23 KiB
C
#include "maze_gen.h"
|
|
|
|
#include <stdio.h>
|
|
#include <time.h>
|
|
|
|
#include "data_queue.h"
|
|
|
|
void (*gen_funs[GEN_SIZE])(maze*) = {&maze_test, &random_maze_ab, &random_maze_wilson, &random_maze_hklinear,
|
|
&random_maze_hkdfs, &random_maze_hkrandom, &random_maze_prim, &random_maze_kruskal,
|
|
&random_maze_rec};
|
|
const char* gen_names[GEN_SIZE] = {"Test (pas de génération)",
|
|
"Aldous-Broder",
|
|
"Wilson",
|
|
"Hunt & Kill: Linéaire",
|
|
"Hunt & Kill: DFS",
|
|
"Hunt & Kill: Aléatoire",
|
|
"Prim",
|
|
"Kruskal",
|
|
"Récursif"};
|
|
|
|
// FONCTIONS AUXILLIAIRES
|
|
// Fonction auxilliaire qui retourne vrai si la cellule à au moins une cellule adjacente non visitée accessible
|
|
static bool has_adj_no_visited(maze* lab, bool* visited, int cell) {
|
|
for (int i = 0; i < 4; i++) {
|
|
int adj = get_adj_maze(lab, cell, i);
|
|
if (adj != -1 && is_reach_maze(lab, adj) && !visited[get_adj_maze(lab, cell, i)]) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Fonction qui renvoie la hsize (taille horizontale) d'un labyrinthe
|
|
static int get_hsize(maze* lab) { return lab->hsize; }
|
|
|
|
// Fonction qui renvoie la vsize (taille verticale) d'un labyrinthe
|
|
static int get_vsize(maze* lab) { return lab->vsize; }
|
|
|
|
// Fonction auxilliaire pour la boucle kill de la génération de labyrinthe hunt & kill et pour le choix de la cellule de Wilson
|
|
static int boucle_kill_direction(maze* lab, bool* visited, int cell) {
|
|
int dir[4] = {0, 1, 2, 3}; // Tableau des directions possibles
|
|
int size = 4;
|
|
bool found_dir = false;
|
|
// Tant qu'il reste des directions possibles et qu'on n'en a pas tiré de valide
|
|
while (size > 0 && !found_dir) {
|
|
const int r = rand() % size;
|
|
int c = dir[r]; // On tire une direction aléatoire
|
|
// On récupère la cellule adjacente dans la direction tirée
|
|
int new_cell = get_adj_maze(lab, cell, c);
|
|
// Si on peut se déplacer dans la direction tirée et que la cellule n'a pas été visitée et est accessible
|
|
if (new_cell != -1 && valid_maze(lab, new_cell) && is_reach_maze(lab, new_cell) && !visited[new_cell]) {
|
|
// On a trouvé une direction valide
|
|
found_dir = true;
|
|
del_wall_maze(lab, cell, c); // On détruit le mur
|
|
cell = new_cell; // On se déplace
|
|
}
|
|
// Sinon on supprime la direction prise du tableau et on décalle les directions pour recommencer avec les directions restantes
|
|
for (int i = r; i < size - 1; i++) {
|
|
dir[i] = dir[i + 1];
|
|
}
|
|
size--;
|
|
}
|
|
return cell;
|
|
}
|
|
|
|
// Fonction auxilliaire qui renvoie une cellule de départ aléatoire
|
|
static int get_start_cell(maze* lab) {
|
|
// On récupère les dimensions du labyrinthe
|
|
int hsize = get_hsize(lab); // Taille horizontale
|
|
int vsize = get_vsize(lab); // Taille verticale
|
|
|
|
// Initialisation de la cellule de départ
|
|
int cell = rand() % (hsize * vsize);
|
|
// On vérifie que la cellule est accessible
|
|
int* tab = malloc(sizeof(int) * hsize * vsize);
|
|
for (int i = 0; i < hsize * vsize; i++) {
|
|
tab[i] = i;
|
|
}
|
|
int count = hsize * vsize;
|
|
while (!is_reach_maze(lab, cell)) {
|
|
// On choisit une cellule aléatoire
|
|
int ind_rand = rand() % count;
|
|
cell = tab[ind_rand];
|
|
if (!is_reach_maze(lab, cell)) {
|
|
// On échange la cellule choisie avec la dernière cellule du tableau
|
|
tab[ind_rand] = tab[count - 1];
|
|
count--;
|
|
}
|
|
}
|
|
free(tab);
|
|
return cell;
|
|
}
|
|
|
|
// FONCTIONS DE GENERATION DU .h
|
|
void maze_test(maze* lab) {
|
|
if (lab == NULL) {
|
|
ERROR("Pointeur de labyrinthe null");
|
|
}
|
|
}
|
|
|
|
void random_maze_ab(maze* lab) {
|
|
if (lab == NULL) {
|
|
ERROR("Pointeur de labyrinthe null");
|
|
}
|
|
// On récupère les dimensions du labyrinthe
|
|
int hsize = get_hsize(lab); // Taille horizontale
|
|
int vsize = get_vsize(lab); // Taille verticale
|
|
|
|
// Création d'un tableau repertoriant si une cellule a été visitée
|
|
bool* visited = malloc(hsize * vsize * sizeof(bool));
|
|
for (int i = 0; i < hsize * vsize; i++) {
|
|
visited[i] = false;
|
|
}
|
|
// Création d'un compteur du nombre de cellules visitées
|
|
int nb_visited = 0;
|
|
|
|
// Initialisation de la cellule de départ
|
|
int cell = get_start_cell(lab);
|
|
|
|
// Cette cellule est visitée
|
|
visited[cell] = true;
|
|
nb_visited++;
|
|
|
|
// Tant que toutes les cellules accessibles n'ont pas été visitées
|
|
while (nb_visited != lab->nb_reachable) {
|
|
// On choisit une direction aléatoire
|
|
int dir = rand() % 4;
|
|
// On récupère la cellule adjacente dans la direction tirée
|
|
int cell_adj = get_adj_maze(lab, cell, dir);
|
|
// Si on peut se déplacer dans la direction tirée et que la cellule n'a pas été visitée et est accessible
|
|
// On détruit le mur entre les deux cellules
|
|
if (cell_adj != -1 && valid_maze(lab, cell_adj) && is_reach_maze(lab, cell_adj) && !visited[cell_adj]) {
|
|
del_wall_maze(lab, cell, dir);
|
|
visited[cell_adj] = true; // On marque la cellule adjacente comme visitée
|
|
nb_visited++; // On incrémente le nombre de cellules visitées
|
|
cell = cell_adj; // On se déplace
|
|
}
|
|
// Sinon si la cellule adjacente est accessible mais a déjà été visitée
|
|
else if (cell_adj != -1 && valid_maze(lab, cell_adj) && is_reach_maze(lab, cell_adj)) {
|
|
cell = cell_adj;
|
|
}
|
|
}
|
|
free(visited);
|
|
}
|
|
|
|
void random_maze_wilson(maze* lab) {
|
|
if (lab == NULL) {
|
|
ERROR("Pointeur de labyrinthe null");
|
|
}
|
|
// On récupère les dimensions du labyrinthe
|
|
int hsize = get_hsize(lab); // Taille horizontale
|
|
int vsize = get_vsize(lab); // Taille verticale
|
|
|
|
// Création d'un tableau repertoriant si une cellule a été visitée
|
|
bool* visited = malloc(hsize * vsize * sizeof(bool));
|
|
for (int i = 0; i < hsize * vsize; i++) {
|
|
visited[i] = false;
|
|
}
|
|
|
|
// Création d'une files pour stocker la marche aléatoire
|
|
queue* queue_walk = create_queue();
|
|
|
|
// Création d'un compteur du nombre de cellules visitées
|
|
int nb_visited = 0;
|
|
|
|
// Initialisation de la cellule de départ
|
|
int cell_start = get_start_cell(lab);
|
|
|
|
// Cette cellule est visitée
|
|
visited[cell_start] = true;
|
|
nb_visited++;
|
|
|
|
// Tant que toutes les cellules accessibles n'ont pas été visitées
|
|
while (nb_visited != lab->nb_reachable) {
|
|
int cell_walk = cell_start;
|
|
// On choisit aléatoirement une cellule non visitée
|
|
while (visited[cell_walk]) {
|
|
cell_walk = get_start_cell(lab);
|
|
}
|
|
enqueue(cell_walk, queue_walk);
|
|
|
|
// On effectue une marche aléatoire jusqu'à atteindre une cellule visitée
|
|
while (!visited[cell_walk]) {
|
|
// On choisit une direction aléatoire
|
|
int dir = rand() % 4;
|
|
// On récupère la cellule adjacente dans la direction tirée
|
|
int cell_adj = get_adj_maze(lab, cell_walk, dir);
|
|
// Si on peut se déplacer dans la direction tirée et que la cellule est accessible
|
|
if (cell_adj != -1 && valid_maze(lab, cell_adj) && is_reach_maze(lab, cell_adj)) {
|
|
cell_walk = cell_adj; // On se déplace
|
|
enqueue(cell_walk, queue_walk); // On ajoute la cellule à la marche aléatoire
|
|
}
|
|
}
|
|
|
|
// On élime les cycles de la marche aléatoire on part du début de la marche aléatoire
|
|
// Pour chaque cellule si elle revient dans la marche aléatoire on supprime les cellules entre les deux
|
|
// On marque les cellules de la marche aléatoire comme visitées et on casse les murs
|
|
int cell_che = dequeue(queue_walk);
|
|
while (!is_empty_queue(queue_walk)) {
|
|
if (!visited[cell_che]) {
|
|
visited[cell_che] = true;
|
|
nb_visited++;
|
|
}
|
|
|
|
// Si elle revient dans la marche aléatoire ou dequeue toutes les cellules entre les deux
|
|
bool found_in_walk = false;
|
|
int count = 0;
|
|
for (int i = 0; i < getsize_queue(queue_walk); i++) {
|
|
if (read_queue(queue_walk, i) == cell_che) {
|
|
found_in_walk = true;
|
|
count = i;
|
|
break;
|
|
}
|
|
}
|
|
if (found_in_walk) {
|
|
while (getsize_queue(queue_walk) != count) {
|
|
dequeue(queue_walk);
|
|
}
|
|
}
|
|
if (!is_empty_queue(queue_walk)) {
|
|
// On récupère la cellule suivante et on casse le mur entre les deux
|
|
int next_cell = dequeue(queue_walk);
|
|
for (int dir = 0; dir < 4; dir++) {
|
|
if (get_adj_maze(lab, cell_che, dir) == next_cell) {
|
|
del_wall_maze(lab, cell_che, dir);
|
|
}
|
|
}
|
|
cell_che = next_cell;
|
|
}
|
|
}
|
|
// On marque la dernière cellule de la marche aléatoire comme visitée
|
|
if (!visited[cell_che]) {
|
|
visited[cell_che] = true;
|
|
nb_visited++;
|
|
}
|
|
}
|
|
free(visited);
|
|
delete_queue(queue_walk);
|
|
}
|
|
|
|
void random_maze_hkdfs(maze* lab) {
|
|
if (lab == NULL) {
|
|
ERROR("Pointeur de labyrinthe null");
|
|
}
|
|
// Récupération des dimensions du labyrinthe
|
|
int hsize = get_hsize(lab); // Taille horizontale
|
|
int vsize = get_vsize(lab); // Taille verticale
|
|
|
|
// Création d'un tableau repertoriant si une cellule a été visitée
|
|
bool* visited = malloc(hsize * vsize * sizeof(bool));
|
|
for (int i = 0; i < hsize * vsize; i++) {
|
|
visited[i] = false;
|
|
}
|
|
// Création d'un compteur du nombre de cellules visitées
|
|
int nb_visited = 0;
|
|
|
|
// Initialisation d'une pile stockant les cellules visitées pour le DFS
|
|
dynarray* stack = create_dyn();
|
|
|
|
// Initialisation de la cellule de départ
|
|
int cell = get_start_cell(lab);
|
|
|
|
// Cette cellule est visitée
|
|
visited[cell] = true;
|
|
nb_visited++;
|
|
push_dyn(cell, stack); // On empile la cellule
|
|
|
|
// Tant que toutes les cellules accessibles n'ont pas été visitées
|
|
while (nb_visited != lab->nb_reachable) {
|
|
// BOUCLE HUNT
|
|
// On regarde si la dernière cellule visitée à une voisin non visitée jusqu'à trouver une cellule
|
|
bool found_hunt = false;
|
|
while (!found_hunt) {
|
|
int hunt = pop_dyn(stack); // On dépile la cellule
|
|
// On regarde si une de ses voisines n'a pas été visitée si c'est le cas, on se déplace dans cette cellule
|
|
if (has_adj_no_visited(lab, visited, hunt)) {
|
|
cell = hunt;
|
|
found_hunt = true;
|
|
}
|
|
}
|
|
push_dyn(cell, stack); // On empile la cellule
|
|
|
|
// BOUCLE KILL
|
|
// Détruire un mur aléatoire tant que toutes les cellules voisines n'ont pas été visitées pour créer un long couloir/chemin
|
|
while (has_adj_no_visited(lab, visited, cell)) { // Tant que cell a une voisine non visitée
|
|
// On recupère une cellule adjacente non visitée
|
|
cell = boucle_kill_direction(lab, visited, cell);
|
|
visited[cell] = true;
|
|
nb_visited++;
|
|
push_dyn(cell, stack);
|
|
}
|
|
}
|
|
free(visited);
|
|
free_dyn(stack);
|
|
}
|
|
|
|
void random_maze_hkrandom(maze* lab) {
|
|
if (lab == NULL) {
|
|
ERROR("Pointeur de labyrinthe null");
|
|
}
|
|
// Récupération des dimensions du labyrinthe
|
|
int hsize = get_hsize(lab); // Taille horizontale
|
|
int vsize = get_vsize(lab); // Taille verticale
|
|
|
|
// Création d'un tableau repertoriant si une cellule a été visitée
|
|
bool* visited = malloc(hsize * vsize * sizeof(bool));
|
|
for (int i = 0; i < hsize * vsize; i++) {
|
|
visited[i] = false;
|
|
}
|
|
|
|
// Création d'un tableau repetoriant les cellules visitées et un compteur qui permet de savoir combien de cellules ont été visitées et avec ou sans
|
|
// Voisins adjacents
|
|
int* visited_cells = malloc(hsize * vsize * sizeof(int));
|
|
int nb_visited = 0;
|
|
int nb_visited_total = 0;
|
|
|
|
// Initialisation de la cellule de départ
|
|
int cell = rand() % (hsize * vsize);
|
|
// On vérifie que la cellule est accessible
|
|
int* tab = malloc(sizeof(int) * hsize * vsize);
|
|
for (int i = 0; i < hsize * vsize; i++) {
|
|
tab[i] = i;
|
|
}
|
|
int count = hsize * vsize;
|
|
while (!is_reach_maze(lab, cell)) {
|
|
// On choisit une cellule aléatoire
|
|
int ind_rand = rand() % count;
|
|
cell = tab[ind_rand];
|
|
if (!is_reach_maze(lab, cell)) {
|
|
// On échange la cellule choisie avec la dernière cellule du tableau
|
|
tab[ind_rand] = tab[count - 1];
|
|
count--;
|
|
}
|
|
}
|
|
free(tab);
|
|
// Cette cellule est visitée
|
|
visited[cell] = true;
|
|
visited_cells[0] = cell;
|
|
nb_visited++;
|
|
nb_visited_total++;
|
|
|
|
// Tant que toutes les cellules n'ont pas été visitées
|
|
while (nb_visited_total != lab->nb_reachable) {
|
|
// BOUCLE HUNT
|
|
// On choisit une cellule aléatoire parmis les cellules visitées
|
|
bool found_hunt = false;
|
|
while (!found_hunt) {
|
|
// On tire une cellule aléatoire parmis le tableau des cellules
|
|
// Visitées
|
|
int ind_hunt = rand() % nb_visited;
|
|
// On regarde si une de ses voisines n'a pas été visitée si c'est le
|
|
// Cas, on se déplace dans cette cellule
|
|
if (has_adj_no_visited(lab, visited, visited_cells[ind_hunt])) {
|
|
cell = visited_cells[ind_hunt];
|
|
found_hunt = true;
|
|
} else {
|
|
// La cellule n'a pas de voisins non visités
|
|
// On la retire du tableau des cellules visitées car on n'a plus besoin de la tester
|
|
visited_cells[ind_hunt] = visited_cells[nb_visited - 1];
|
|
nb_visited--;
|
|
}
|
|
}
|
|
|
|
// BOUCLE KILL
|
|
// Détruire un mur aléatoire tant que toutes les cellules voisines n'ont pas été visitées pour créer un long couloir/chemin
|
|
while (has_adj_no_visited(lab, visited, cell)) { // Tant que cell a une voisine non visitée
|
|
// On recupère une cellule adjacente non visitée
|
|
cell = boucle_kill_direction(lab, visited, cell);
|
|
visited[cell] = true;
|
|
visited_cells[nb_visited] = cell;
|
|
nb_visited++;
|
|
nb_visited_total++;
|
|
}
|
|
}
|
|
free(visited);
|
|
free(visited_cells);
|
|
}
|
|
|
|
void random_maze_hklinear(maze* lab) {
|
|
if (lab == NULL) {
|
|
ERROR("Pointeur de labyrinthe null");
|
|
}
|
|
// Récupération des dimensions du labyrinthe
|
|
int hsize = get_hsize(lab); // Taille horizontale
|
|
int vsize = get_vsize(lab); // Taille verticale
|
|
|
|
// Création d'un tableau repertoriant si une cellule a été visitée
|
|
bool* visited = malloc(hsize * vsize * sizeof(bool));
|
|
for (int i = 0; i < hsize * vsize; i++) {
|
|
visited[i] = false;
|
|
}
|
|
// Création d'un compteur du nombre de cellules visitées
|
|
int nb_visited = 0;
|
|
|
|
// Initialisation de la cellule de départ
|
|
int cell = get_start_cell(lab);
|
|
|
|
// Cette cellule est visitée
|
|
visited[cell] = true;
|
|
nb_visited++;
|
|
|
|
// Tant que toutes les cellules n'ont pas été visitées
|
|
while (nb_visited != lab->nb_reachable) {
|
|
// BOUCLE HUNT
|
|
// On parcourt toutes les cellules
|
|
bool found_hunt = false;
|
|
int hunt = 0;
|
|
while (!found_hunt && hunt < hsize * vsize) {
|
|
// Si la cellule a été visitée on regarde si une de ses voisines n'a pas été visitée si c'est le cas, on se déplace dans cette cellule
|
|
if (visited[hunt]) {
|
|
if (has_adj_no_visited(lab, visited, hunt)) {
|
|
cell = hunt;
|
|
found_hunt = true;
|
|
}
|
|
}
|
|
hunt++;
|
|
}
|
|
|
|
// BOUCLE KILL
|
|
// Détruire un mur aléatoire tant que toutes les cellules voisines n'ont pas été visitées pour créer un long couloir/chemin
|
|
while (has_adj_no_visited(lab, visited, cell)) { // Tant que cell a une voisine non visitée
|
|
// On recupère une cellule adjacente non visitée
|
|
cell = boucle_kill_direction(lab, visited, cell);
|
|
visited[cell] = true; // On marque la cellule comme visitée
|
|
nb_visited++; // On incrémente le nombre de cellules visitées
|
|
}
|
|
}
|
|
free(visited);
|
|
}
|
|
|
|
// Structure pour représenter une arête
|
|
typedef struct {
|
|
int cell1; // Première cellule de l'arête
|
|
int cell2; // Seconde cellule de l'arête
|
|
cardinal dir; // Direction de l'arête
|
|
} edge;
|
|
|
|
// Fonction pour ajouter une arête à la liste des arêtes à traiter
|
|
static void add_edges(maze* m, int cell, edge* edges, int* edge_count) {
|
|
for (int dir = 0; dir < 4; dir++) {
|
|
int adj_cell = get_adj_maze(m, cell, dir);
|
|
if (adj_cell != -1 && valid_maze(m, adj_cell) && is_reach_maze(m, adj_cell)) {
|
|
edges[*edge_count].cell1 = cell;
|
|
edges[*edge_count].cell2 = adj_cell;
|
|
edges[*edge_count].dir = dir;
|
|
(*edge_count)++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void random_maze_prim(maze* m) {
|
|
srand(time(NULL));
|
|
|
|
int total_cells = m->hsize * m->vsize;
|
|
bool* visited = (bool*)calloc(total_cells, sizeof(bool));
|
|
edge* edges = (edge*)malloc(total_cells * 4 * sizeof(edge)); // Maximum 4 arêtes par cellule
|
|
int edge_count = 0;
|
|
|
|
// Initialisation de la cellule de départ
|
|
int start_cell = get_start_cell(m);
|
|
|
|
visited[start_cell] = true;
|
|
|
|
// Ajouter toutes les arêtes issues de cette cellule à l'ensemble des arêtes à traiter
|
|
add_edges(m, start_cell, edges, &edge_count);
|
|
|
|
// Tant qu'il reste des arêtes à traiter
|
|
while (edge_count > 0) {
|
|
// Choisir une arête aléatoirement et la retirer de l'ensemble des arêtes à traiter
|
|
int rand_index = rand() % edge_count;
|
|
edge chosen_edge = edges[rand_index];
|
|
edges[rand_index] = edges[--edge_count];
|
|
|
|
int cell1 = chosen_edge.cell1;
|
|
int cell2 = chosen_edge.cell2;
|
|
cardinal dir = chosen_edge.dir;
|
|
|
|
// Si la cellule vers laquelle mène cette arête n'a pas encore été visitée
|
|
if (!visited[cell2]) {
|
|
// Casser le mur correspondant à l'arête
|
|
del_wall_maze(m, cell1, dir);
|
|
del_wall_maze(m, cell2, (dir + 2) % 4); // Casser le mur opposé
|
|
fflush(stdout);
|
|
// Ajouter la cellule à l'ensemble des cellules visitées
|
|
visited[cell2] = true;
|
|
|
|
// Ajouter toutes les arêtes issues de cette cellule à l'ensemble des arêtes à traiter
|
|
add_edges(m, cell2, edges, &edge_count);
|
|
}
|
|
}
|
|
|
|
free(visited);
|
|
free(edges);
|
|
}
|
|
|
|
void random_maze_kruskal(maze* lab) {
|
|
if (lab == NULL) {
|
|
ERROR("Pointeur de labyrinthe null");
|
|
}
|
|
// On crée une partition triviale de l'enemble des cellules
|
|
ufind* uf_cell = create_ufind(lab->hsize * lab->vsize);
|
|
// On crée un tableau pour stocker les arêtes
|
|
edge* tab_edges = malloc(lab->hsize * lab->vsize * 4 * sizeof(edge)); // Maximum 4 arêtes par cellule
|
|
// On fait parcours toutes les cellules pour ajouter les arêtes entre les cellules accessibles
|
|
int edge_count = 0;
|
|
for (int i = 0; i < lab->hsize * lab->vsize; i++) {
|
|
// On ajoute les arêtes de la cellule i si i est accessible
|
|
if (is_reach_maze(lab, i)) {
|
|
add_edges(lab, i, tab_edges, &edge_count);
|
|
}
|
|
}
|
|
|
|
// Tant qu'il reste des arêtes à traiter
|
|
while (edge_count > 0) {
|
|
// Choisir une arête aléatoirement et la retirer de l'ensemble des arêtes à traiter
|
|
int rand_index = rand() % edge_count;
|
|
edge chosen_edge = tab_edges[rand_index];
|
|
// On remplace l'arête choisie par la dernière arête du tableau
|
|
tab_edges[rand_index] = tab_edges[edge_count - 1];
|
|
edge_count--;
|
|
|
|
// On récupère les cellules et la direction de l'arête
|
|
int cell1 = chosen_edge.cell1;
|
|
int cell2 = chosen_edge.cell2;
|
|
cardinal dir = chosen_edge.dir; // Cell1 -> cell2
|
|
|
|
// Si les deux cellules ne sont pas dans la même classe
|
|
if (find_ufind(cell1, uf_cell) != find_ufind(cell2, uf_cell)) {
|
|
// Casser le mur correspondant à l'arête
|
|
del_wall_maze(lab, cell1, dir);
|
|
|
|
// Fusionner les deux classes
|
|
union_ufind(cell1, cell2, uf_cell);
|
|
}
|
|
}
|
|
// On free la partition et le tableau des arêtes
|
|
delete_ufind(uf_cell);
|
|
free(tab_edges);
|
|
}
|
|
|
|
void random_maze_rec(maze* m) {
|
|
// Initialiser le générateur de nombres aléatoires
|
|
srand(time(NULL));
|
|
|
|
// Définir une pile pour gérer la récursion manuellement
|
|
typedef struct {
|
|
int x, y, width, height;
|
|
} Region;
|
|
|
|
// Taille maximale de la pile (au pire des cas, on divise chaque cellule individuellement)
|
|
int max_stack_size = m->hsize * m->vsize;
|
|
Region* stack = (Region*)malloc(max_stack_size * sizeof(Region));
|
|
int stack_size = 0;
|
|
|
|
// Pousser la région initiale sur la pile
|
|
stack[stack_size++] = (Region){0, 0, m->hsize, m->vsize};
|
|
|
|
// Boucle principale pour traiter la pile
|
|
while (stack_size > 0) {
|
|
// Pop une région de la pile
|
|
Region current = stack[--stack_size];
|
|
|
|
// Cas de base: si la région est réduite à une seule cellule, on ne fait rien
|
|
if (current.width <= 1 && current.height <= 1) {
|
|
continue;
|
|
}
|
|
|
|
// Choisir de diviser horizontalement ou verticalement
|
|
if (current.height >= current.width) {
|
|
// Diviser horizontalement
|
|
int divide_line = current.y + current.height / 2;
|
|
|
|
// Pousser les deux nouvelles régions sur la pile
|
|
stack[stack_size++] = (Region){current.x, current.y, current.width, divide_line - current.y};
|
|
stack[stack_size++] = (Region){current.x, divide_line, current.width, current.y + current.height - divide_line};
|
|
|
|
// Casser un mur aléatoirement sur la ligne de séparation
|
|
int random_x = current.x + rand() % current.width;
|
|
del_wall_maze(m, divide_line * m->hsize + random_x, NORTH);
|
|
} else {
|
|
// Diviser verticalement
|
|
int divide_column = current.x + current.width / 2;
|
|
|
|
// Pousser les deux nouvelles régions sur la pile
|
|
stack[stack_size++] = (Region){current.x, current.y, divide_column - current.x, current.height};
|
|
stack[stack_size++] = (Region){divide_column, current.y, current.x + current.width - divide_column, current.height};
|
|
|
|
// Casser un mur aléatoirement sur la colonne de séparation
|
|
int random_y = current.y + rand() % current.height;
|
|
del_wall_maze(m, random_y * m->hsize + divide_column, WEST);
|
|
}
|
|
}
|
|
// Libérer la mémoire allouée pour la pile
|
|
free(stack);
|
|
}
|