ajouts des fichiers perso
Le plagiat c'est mal donc gare à vos culs
This commit is contained in:
509
maze_gen/maze_gen_VM.c
Normal file
509
maze_gen/maze_gen_VM.c
Normal file
@@ -0,0 +1,509 @@
|
||||
#include "maze_gen.h"
|
||||
#include "data_binheap.h"
|
||||
#include "maze.h"
|
||||
#include "maze_2.h"
|
||||
|
||||
#include <sys/random.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"};
|
||||
|
||||
void maze_test(maze *)
|
||||
{
|
||||
// ne fait rien
|
||||
}
|
||||
|
||||
void random_maze_ab(maze *p_maze)
|
||||
{
|
||||
bool visited[p_maze->hsize * p_maze->vsize]; // Tableau de booléens pour savoir si une case a été visitée
|
||||
int visited_count = 0; // nombre de cases à visiter
|
||||
for (int i = 0; i < p_maze->hsize * p_maze->vsize; i++)
|
||||
{
|
||||
visited[i] = false; // aucune case n'a été visitée
|
||||
if (can_be_used(p_maze, i))
|
||||
{
|
||||
visited_count++; // on incrémente le nombre de cases à visiter
|
||||
}
|
||||
}
|
||||
uint cell;
|
||||
do
|
||||
{
|
||||
getrandom(&cell, sizeof(cell), 0);
|
||||
cell %= p_maze->hsize * p_maze->vsize;
|
||||
}
|
||||
while (!can_be_used(p_maze, cell)); // on cherche une case utilisable
|
||||
|
||||
visited[cell] = true; // on visite la case de départ
|
||||
visited_count--;
|
||||
while (visited_count > 0)
|
||||
{
|
||||
const cardinal card = rand() % 4; // direction aléatoire
|
||||
const int neigbour = get_adj_maze(p_maze, cell, card); // case voisine
|
||||
if (can_be_used(p_maze, neigbour)) // si le voisin est exploitable
|
||||
{
|
||||
if (!visited[neigbour])
|
||||
// si la case voisine n'a pas été visitée, on la visite
|
||||
{
|
||||
const int diff = cell - neigbour;
|
||||
if (diff == 1)
|
||||
{
|
||||
del_wall_maze(p_maze, cell, WEST);
|
||||
}
|
||||
else if (diff == -1)
|
||||
{
|
||||
del_wall_maze(p_maze, cell, EAST);
|
||||
}
|
||||
else if (diff == p_maze->hsize)
|
||||
{
|
||||
del_wall_maze(p_maze, cell, NORTH);
|
||||
}
|
||||
else if (diff == -p_maze->hsize)
|
||||
{
|
||||
del_wall_maze(p_maze, cell, SOUTH);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Erreur rma: les cases ne sont pas voisines\n");
|
||||
free_maze(p_maze);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
visited[neigbour] = true;
|
||||
visited_count--;
|
||||
}
|
||||
cell = neigbour; // on se déplace
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void random_maze_wilson(maze *p_maze)
|
||||
{
|
||||
bool visited[p_maze->hsize * p_maze->vsize]; // Tableau de booléens pour savoir si une case a été visitée
|
||||
int visited_count = p_maze->hsize * p_maze->vsize - 1;
|
||||
// nombre de case à visiter (la case de départ est déjà visitée)
|
||||
for (int i = 0; i < p_maze->hsize * p_maze->vsize; i++)
|
||||
{
|
||||
if (can_be_used(p_maze, i))
|
||||
// si la case est accessible
|
||||
{
|
||||
visited[i] = false; // on doit la visiter
|
||||
}
|
||||
else
|
||||
{
|
||||
visited_count--; // on décrémente le nombre de cases à visiter
|
||||
}
|
||||
}
|
||||
int cell;
|
||||
do
|
||||
{
|
||||
getrandom(&cell, sizeof(cell), 0);
|
||||
cell %= p_maze->hsize * p_maze->vsize;
|
||||
}
|
||||
while (!can_be_used(p_maze, cell)); // on cherche une case utilisable
|
||||
|
||||
visited[cell] = true; // on visite la case de départ
|
||||
while (visited_count > 0) // recherche d'une case non visitée
|
||||
{
|
||||
do
|
||||
{
|
||||
cell = rand() % (p_maze->hsize * p_maze->vsize); // case aléatoire
|
||||
}
|
||||
while (visited[cell] || !can_be_used(p_maze, cell)); // tant que la case a été visitée ou n'est pas utilisable
|
||||
|
||||
bool path_visited[p_maze->hsize * p_maze->vsize]; // Tableau de booléens pour savoir si une case a été visitée
|
||||
for (int i = 0; i < p_maze->hsize * p_maze->vsize; i++)
|
||||
{
|
||||
path_visited[i] = false; // aucune case n'a été visitée
|
||||
}
|
||||
|
||||
// hérence jusqu'à une case visitée
|
||||
dynarray *path = create_dyn(); // liste des cases du chemin
|
||||
push_dyn(cell, path); // on initialise le chemin
|
||||
path_visited[cell] = true; // la case est visitée
|
||||
int neighbour; // case voisine
|
||||
cardinal card; // direction aléatoire
|
||||
while (!visited[cell]) // tant que la case n'a pas été visitée
|
||||
{
|
||||
push_dyn(cell, path); // on ajoute la case au chemin
|
||||
|
||||
do // on cherche un voisin
|
||||
{
|
||||
getrandom(&card, sizeof(card), 0);
|
||||
card %= 4;
|
||||
neighbour = get_adj_maze(p_maze, cell, card); // case voisine
|
||||
}
|
||||
while (!can_be_used(p_maze, neighbour)); // jusqu'à trouver un voisin convenable
|
||||
|
||||
cell = neighbour; // on se déplace
|
||||
|
||||
// résolution des cycles
|
||||
while (path_visited[cell] && !is_empty_dyn(path)) // si la case a déjà été visitée, c'est un cycle
|
||||
{
|
||||
path_visited[cell] = false; // on efface le chemin en remontant le cycle
|
||||
cell = pop_dyn(path);
|
||||
}
|
||||
path_visited[cell] = true; // on marque la case dans le chemin
|
||||
}
|
||||
|
||||
int cell1 = pop_dyn(path); // cell1 est la cellule sur le chemin (pas encore visitée)
|
||||
// on casse les murs
|
||||
while (!is_empty_dyn(path)) // tant qu'il reste des cases sur le chemin
|
||||
{
|
||||
const int diff = cell - cell1;
|
||||
if (diff == 1)
|
||||
{
|
||||
del_wall_maze(p_maze, cell, WEST);
|
||||
}
|
||||
else if (diff == -1)
|
||||
{
|
||||
del_wall_maze(p_maze, cell, EAST);
|
||||
}
|
||||
else if (diff == p_maze->hsize)
|
||||
{
|
||||
del_wall_maze(p_maze, cell, NORTH);
|
||||
}
|
||||
else if (diff == -p_maze->hsize)
|
||||
{
|
||||
del_wall_maze(p_maze, cell, SOUTH);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Erreur rma: les cases ne sont pas voisines\n");
|
||||
free_maze(p_maze);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
visited[cell1] = true; // la case est visitée
|
||||
visited_count--; // on décrémente le nombre de cases à visiter
|
||||
cell = cell1; // la cellule actuelle devient la cellule précédente (visitée)
|
||||
cell1 = pop_dyn(path); // la cellule précédente devient la cellule chemin (pas encore visitée)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void phase_kill_hkdfs(maze *p_maze, bool *visited, int cell, dynarray *d)
|
||||
{
|
||||
visited[cell] = true; // on visite la case où nous sommes
|
||||
// int dir_tab[4] = {0};
|
||||
// tableau de booléens pour savoir si une direction est possible
|
||||
int possible_dir = 0; // nombre de directions possibles
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
int neighbour = get_adj_maze(p_maze, cell, i); // case voisine
|
||||
if (neighbour != -1 && !visited[neighbour] && can_be_used(p_maze, neighbour))
|
||||
{
|
||||
// si la case voisine existe et n'a pas été visitée
|
||||
// dir_tab[i] = true;
|
||||
possible_dir++;
|
||||
}
|
||||
}
|
||||
if (possible_dir == 0)
|
||||
{
|
||||
// si aucune direction n'est possible, on retourne
|
||||
return;
|
||||
}
|
||||
int random_dir = rand() % 4;
|
||||
while (get_adj_maze(p_maze, cell, random_dir) == -1 || visited[get_adj_maze(p_maze, cell, random_dir)] || !can_be_used(p_maze, cell))
|
||||
{
|
||||
random_dir = rand() % 4;
|
||||
}
|
||||
push_dyn(cell, d);
|
||||
del_wall_maze(p_maze, cell, random_dir);
|
||||
phase_kill_hkdfs(p_maze, visited, get_adj_maze(p_maze, cell, random_dir), d);
|
||||
// on continue la phase de kill
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void random_maze_hkdfs(maze *p_maze)
|
||||
{
|
||||
bool visited[p_maze->hsize * p_maze->vsize];
|
||||
// tableau de booléens pour savoir si une case a été visitée
|
||||
for (int i = 0; i < p_maze->hsize * p_maze->vsize; i++)
|
||||
{
|
||||
if (can_be_used(p_maze, i)) // si la case est accessible
|
||||
{
|
||||
visited[i] = false; // on doit la visiter
|
||||
}
|
||||
else
|
||||
{
|
||||
visited[i] = true; // on ne doit pas la visiter
|
||||
}
|
||||
}
|
||||
dynarray *d = create_dyn();
|
||||
// on choisit une case aléatoire, on la visite et on lance la phase de kill
|
||||
int cell; // case aléatoire
|
||||
do
|
||||
{
|
||||
cell = rand() % (p_maze->hsize * p_maze->vsize);
|
||||
}
|
||||
while (visited[cell] || !can_be_used(p_maze, cell));
|
||||
push_dyn(cell, d);
|
||||
phase_kill_hkdfs(p_maze, visited, pop_dyn(d), d);
|
||||
// booléen pour savoir si la case a des voisins visités
|
||||
while (!is_empty_dyn(d))
|
||||
{
|
||||
phase_kill_hkdfs(p_maze, visited, pop_dyn(d), d);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void phase_kill_hkrandom(maze *p_maze, bool *visited, int cell, int *visited_count)
|
||||
{
|
||||
if (!visited[cell])
|
||||
{
|
||||
(*visited_count)--; // on décrémente le nombre de cases à visiter
|
||||
}
|
||||
visited[cell] = true; // on visite la case où nous sommes
|
||||
int dir_tab[4] = {0};
|
||||
// tableau de booléens pour savoir si une direction est possible
|
||||
int possible_dir = 0; // nombre de directions possibles
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
int neighbour = get_adj_maze(p_maze, cell, i); // case voisine
|
||||
if (neighbour != -1 && !visited[neighbour])
|
||||
{
|
||||
// si la case voisine existe et n'a pas été visitée
|
||||
dir_tab[i] = true;
|
||||
possible_dir++;
|
||||
}
|
||||
}
|
||||
if (possible_dir == 0)
|
||||
{
|
||||
// si aucune direction n'est possible, on retourne
|
||||
return;
|
||||
}
|
||||
int random_dir = rand() % possible_dir;
|
||||
while (dir_tab[random_dir] == false)
|
||||
{
|
||||
// on cherche une direction possible
|
||||
random_dir = (random_dir + 1) % 4;
|
||||
}
|
||||
del_wall_maze(p_maze, cell, random_dir);
|
||||
phase_kill_hkrandom(p_maze, visited, get_adj_maze(p_maze, cell, random_dir), visited_count);
|
||||
// on continue la phase de kill
|
||||
return;
|
||||
}
|
||||
|
||||
void random_maze_hkrandom(maze *p_maze)
|
||||
{
|
||||
bool visited[p_maze->hsize * p_maze->vsize];
|
||||
// tableau de booléens pour savoir si une case a été visitée
|
||||
int visited_count = p_maze->hsize * p_maze->vsize;
|
||||
// nombre de cases à visiter
|
||||
for (int i = 0; i < p_maze->hsize * p_maze->vsize; i++)
|
||||
{
|
||||
if (can_be_used(p_maze, i)) // si la case est accessible
|
||||
{
|
||||
visited[i] = false; // on doit la visiter
|
||||
}
|
||||
else
|
||||
{
|
||||
visited[i] = true;
|
||||
visited_count--; // on décrémente le nombre de cases à visiter
|
||||
}
|
||||
}
|
||||
// on choisit une case aléatoire et on lance la phase de kill
|
||||
int cell;
|
||||
do
|
||||
{
|
||||
cell = rand() % (p_maze->hsize * p_maze->vsize);
|
||||
}
|
||||
while (visited[cell] || !can_be_used(p_maze, cell));
|
||||
phase_kill_hkrandom(p_maze, visited, cell, &visited_count);
|
||||
|
||||
while (visited_count > 0)
|
||||
{
|
||||
do
|
||||
{
|
||||
cell = rand() % (p_maze->hsize * p_maze->vsize);
|
||||
}
|
||||
while (!visited[cell] || !can_be_used(p_maze, cell));
|
||||
phase_kill_hkrandom(p_maze, visited, cell, &visited_count);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void phase_kill_hklinear(maze *p_maze, char *visited, int cell, int *cell_min)
|
||||
{
|
||||
visited[cell] = 1; // on visite la case où nous sommes
|
||||
int possible_dir = 0; // nombre de directions possibles
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
int neighbour = get_adj_maze(p_maze, cell, i); // case voisine
|
||||
if (neighbour != -1 && !visited[neighbour] && can_be_used(p_maze, neighbour))
|
||||
{
|
||||
// si la case voisine existe et n'a pas été visitée
|
||||
possible_dir++;
|
||||
}
|
||||
}
|
||||
if (possible_dir == 0)
|
||||
{
|
||||
visited[cell] = 2;
|
||||
return;
|
||||
}
|
||||
|
||||
int random_dir = rand() % 4;
|
||||
while (get_adj_maze(p_maze, cell, random_dir) == -1 || visited[get_adj_maze(p_maze, cell, random_dir)] == 1 ||
|
||||
!can_be_used(p_maze, get_adj_maze(p_maze, cell, random_dir)))
|
||||
{
|
||||
random_dir = rand() % 4;
|
||||
}
|
||||
del_wall_maze(p_maze, cell, random_dir);
|
||||
|
||||
if (cell < *cell_min)
|
||||
*cell_min = cell;
|
||||
phase_kill_hklinear(p_maze, visited, get_adj_maze(p_maze, cell, random_dir), cell_min);
|
||||
// on continue la phase de kill
|
||||
return;
|
||||
}
|
||||
|
||||
void random_maze_hklinear(maze *p_maze)
|
||||
{
|
||||
char visited[p_maze->hsize * p_maze->vsize];
|
||||
// tableau de booléens pour savoir si une case a été visitée
|
||||
// nombre de cases à visiter
|
||||
for (int i = 0; i < p_maze->hsize * p_maze->vsize; i++)
|
||||
{
|
||||
if (can_be_used(p_maze, i)) // si la case est accessible
|
||||
{
|
||||
visited[i] = 0; // on doit la visiter
|
||||
}
|
||||
else
|
||||
{
|
||||
visited[i] = 2; // on ne doit pas la visiter
|
||||
}
|
||||
}
|
||||
// on choisit une case aléatoire, on la visite et on lance la phase de kill
|
||||
int cell;
|
||||
do
|
||||
{
|
||||
cell = rand() % (p_maze->hsize * p_maze->vsize); // case aléatoire}
|
||||
}
|
||||
while (!can_be_used(p_maze, cell));
|
||||
|
||||
phase_kill_hklinear(p_maze, visited, cell, &cell);
|
||||
|
||||
while (cell != p_maze->hsize * p_maze->vsize)
|
||||
{
|
||||
int n_cell = cell;
|
||||
while (visited[n_cell] == 2 || visited[n_cell] == 0)
|
||||
{
|
||||
n_cell++;
|
||||
if (visited[n_cell] == 1 && can_be_used(p_maze, n_cell))
|
||||
{
|
||||
cell = n_cell;
|
||||
}
|
||||
if (n_cell == p_maze->hsize * p_maze->vsize)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
phase_kill_hklinear(p_maze, visited, cell, &cell);
|
||||
}
|
||||
}
|
||||
|
||||
void random_maze_prim(maze *) { return; }
|
||||
|
||||
void random_maze_kruskal(maze *) { return; }
|
||||
|
||||
static void maze_rec(maze *m, const int x, const int y, const int w, const int h)
|
||||
{
|
||||
static int count = 0;
|
||||
printf("%d : ", count++);
|
||||
if (w == 1 && h == 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
unsigned int wall;
|
||||
if (w > h)
|
||||
{
|
||||
const int middle = x + w / 2; //la coordonnée x du mur à casser
|
||||
getrandom(&wall, sizeof(wall), 0);
|
||||
wall = wall % h + y; //la coordonné y du mur à casser
|
||||
del_wall_maze(m, middle * m->vsize + wall, EAST);
|
||||
maze_rec(m, x, y, middle - x, h);
|
||||
maze_rec(m, middle, y, x + w - middle, h);
|
||||
}
|
||||
else
|
||||
{
|
||||
const int middle = y + h / 2; //la coordonnée y du mur à casser
|
||||
getrandom(&wall, sizeof(wall), 0);
|
||||
wall = wall % w + x; //la coordonné x du mur à casser
|
||||
del_wall_maze(m, wall * m->vsize + middle, SOUTH);
|
||||
maze_rec(m, x, y, w, middle - y);
|
||||
maze_rec(m, x, middle, w, y + h - middle);
|
||||
}
|
||||
}
|
||||
|
||||
void random_maze_rec(maze *p_maze){
|
||||
maze_rec(p_maze, 0, 0, p_maze->hsize, p_maze->vsize);
|
||||
}
|
||||
|
||||
static void aloyse_random_maze_rec(maze* m) {
|
||||
// Initialiser le générateur de nombres aléatoires
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user