YouTube-simulations/sub_maze.c

339 lines
10 KiB
C
Raw Normal View History

2022-10-18 23:28:20 +02:00
/* Warning: the function init_maze does not always return a maze with a solution */
/* The current algorithm uses a self-avoiding random walk. A better option may be */
/* to give random weights to the dual graph, and finite a maximal spanning tree */
/* Change constant RAND_SHIFT to change the maze */
typedef struct
{
short int nneighb; /* number of neighbours */
int neighb[MAZE_MAX_NGBH]; /* neighbour cells */
short int directions[MAZE_MAX_NGBH]; /* direction of neighbours */
short int north, east, south, west; /* closed walls */
short int active; /* takes value 1 if currently active in RW path */
short int tested; /* takes value 1 if tested */
2022-11-20 23:17:39 +01:00
short int connected; /* takes value 1 if connected to exit */
short int closed; /* takes value 1 if no untested neighbours */
2022-10-18 23:28:20 +02:00
} t_maze;
int nmaze(int i, int j)
{
return(NXMAZE*j + i);
}
void init_maze_graph(t_maze maze[NXMAZE*NYMAZE])
{
int i, j, k, n;
printf("Initializing maze\n");
/* initialize neighbours */
/* in the bulk */
for (i=1; i<NXMAZE-1; i++)
for (j=1; j<NYMAZE-1; j++)
{
n = nmaze(i, j);
maze[n].nneighb = 4;
maze[n].neighb[0] = nmaze(i, j+1);
maze[n].neighb[1] = nmaze(i+1, j);
maze[n].neighb[2] = nmaze(i, j-1);
maze[n].neighb[3] = nmaze(i-1, j);
for (k=0; k<4; k++) maze[n].directions[k] = k;
}
/* left side */
for (j=1; j<NYMAZE-1; j++)
{
n = nmaze(0, j);
maze[n].nneighb = 3;
maze[n].neighb[0] = nmaze(0, j+1);
maze[n].neighb[1] = nmaze(1, j);
maze[n].neighb[2] = nmaze(0, j-1);
for (k=0; k<3; k++) maze[n].directions[k] = k;
}
/* right side */
for (j=1; j<NYMAZE-1; j++)
{
n = nmaze(NXMAZE-1, j);
maze[n].nneighb = 3;
maze[n].neighb[0] = nmaze(NXMAZE-1, j+1);
maze[n].neighb[1] = nmaze(NXMAZE-2, j);
maze[n].neighb[2] = nmaze(NXMAZE-1, j-1);
maze[n].directions[0] = 0;
maze[n].directions[1] = 3;
maze[n].directions[2] = 2;
}
/* bottom side */
for (i=1; i<NXMAZE-1; i++)
{
n = nmaze(i, 0);
maze[n].nneighb = 3;
maze[n].neighb[0] = nmaze(i, 1);
maze[n].neighb[1] = nmaze(i+1, 0);
maze[n].neighb[2] = nmaze(i-1, 0);
maze[n].directions[0] = 0;
maze[n].directions[1] = 1;
maze[n].directions[2] = 3;
}
/* top side */
for (i=1; i<NXMAZE-1; i++)
{
n = nmaze(i, NYMAZE-1);
maze[n].nneighb = 3;
maze[n].neighb[0] = nmaze(i, NYMAZE-2);
maze[n].neighb[1] = nmaze(i+1, NYMAZE-1);
maze[n].neighb[2] = nmaze(i-1, NYMAZE-1);
maze[n].directions[0] = 2;
maze[n].directions[1] = 1;
maze[n].directions[2] = 3;
}
/* corners */
n = nmaze(0,0);
maze[n].nneighb = 2;
maze[n].neighb[0] = nmaze(1,0);
maze[n].neighb[1] = nmaze(0,1);
maze[n].directions[0] = 1;
maze[n].directions[1] = 0;
n = nmaze(NXMAZE-1,0);
maze[n].nneighb = 2;
maze[n].neighb[0] = nmaze(NXMAZE-2,0);
maze[n].neighb[1] = nmaze(NXMAZE-1,1);
maze[n].directions[0] = 3;
maze[n].directions[1] = 0;
n = nmaze(0,NYMAZE-1);
maze[n].nneighb = 2;
maze[n].neighb[0] = nmaze(1,NYMAZE-1);
maze[n].neighb[1] = nmaze(0,NYMAZE-2);
maze[n].directions[0] = 1;
maze[n].directions[1] = 2;
n = nmaze(NXMAZE-1,NYMAZE-1);
maze[n].nneighb = 2;
maze[n].neighb[0] = nmaze(NXMAZE-2,NYMAZE-1);
maze[n].neighb[1] = nmaze(NXMAZE-1,NYMAZE-2);
maze[n].directions[0] = 3;
maze[n].directions[1] = 2;
/* initialize other parameters */
for (i=0; i<NXMAZE; i++)
for (j=0; j<NYMAZE; j++)
{
n = nmaze(i, j);
maze[n].active = 0;
maze[n].tested = 0;
2022-11-20 23:17:39 +01:00
maze[n].connected = 0;
maze[n].closed = 0;
2022-10-18 23:28:20 +02:00
maze[n].north = 1;
maze[n].east = 1;
maze[n].south = 1;
maze[n].west = 1;
}
}
2022-11-20 23:17:39 +01:00
int find_maze_path(t_maze maze[NXMAZE*NYMAZE], int n0, int *path, int *pathlength)
2022-10-18 23:28:20 +02:00
/* find a random walk path in the maze */
2022-11-20 23:17:39 +01:00
/* returns 0 or 1 depending on whether path reaches a tested cell or a deadend */
2022-10-18 23:28:20 +02:00
{
2022-11-20 23:17:39 +01:00
int active_counter = 0, i, n = n0, npaths, inext, nextcell, trial, nnext, deadend = 1, length = 0;
2022-10-18 23:28:20 +02:00
int next_table[4];
/* contruct random walk */
npaths = maze[n].nneighb;
2022-11-20 23:17:39 +01:00
path[0] = n0;
2022-10-18 23:28:20 +02:00
// while ((npaths > 0)&&(!maze[n].tested))
while ((npaths > 0))
{
maze[n].active = 1;
printf("Cell (%i, %i) ", n%NXMAZE, n/NXMAZE);
nnext = 0;
for (i=0; i<npaths; i++)
{
nextcell = maze[n].neighb[i];
2022-11-20 23:17:39 +01:00
if ((!maze[nextcell].active)&&((maze[nextcell].connected)||(!maze[nextcell].tested)))
2022-10-18 23:28:20 +02:00
{
next_table[nnext] = i;
nnext++;
}
}
if (nnext == 0)
{
2022-11-20 23:17:39 +01:00
deadend = 1;
2022-10-18 23:28:20 +02:00
printf("Ended path\n");
// sleep(5);
npaths = 0;
2022-11-20 23:17:39 +01:00
maze[n].closed = 1;
2022-10-18 23:28:20 +02:00
}
else
{
2022-11-20 23:17:39 +01:00
deadend = 0;
2022-10-18 23:28:20 +02:00
inext = next_table[rand()%nnext];
nextcell = maze[n].neighb[inext];
switch(maze[n].directions[inext]){
case(0):
{
printf("Moving north\n");
maze[n].north = 0;
maze[nextcell].south = 0;
break;
}
case(1):
{
printf("Moving east\n");
maze[n].east = 0;
maze[nextcell].west = 0;
break;
}
case(2):
{
printf("Moving south\n");
maze[n].south = 0;
maze[nextcell].north = 0;
break;
}
case(3):
{
printf("Moving west\n");
maze[n].west = 0;
maze[nextcell].east = 0;
break;
}
}
n = nextcell;
if (maze[n].tested) npaths = 0;
else npaths = maze[n].nneighb;
active_counter++;
2022-11-20 23:17:39 +01:00
if (length < NXMAZE*NYMAZE)
{
length++;
path[length] = n;
}
deadend = 0;
2022-10-18 23:28:20 +02:00
}
}
2022-11-20 23:17:39 +01:00
printf("Reached tested cell (%i, %i)\n", n%NXMAZE, n/NXMAZE);
if (!maze[n].connected) deadend = 1;
2022-10-18 23:28:20 +02:00
/* update cell status */
for (n=0; n<NXMAZE*NYMAZE; n++) if (maze[n].active)
{
maze[n].active = 0;
maze[n].tested = 1;
}
printf("Ended path\n");
2022-11-20 23:17:39 +01:00
if (deadend) printf("Deadend\n");
*pathlength = length;
printf("Path length %i \n", length);
2022-10-18 23:28:20 +02:00
2022-11-20 23:17:39 +01:00
return(deadend);
// return(active_counter);
2022-10-18 23:28:20 +02:00
}
2022-11-20 23:17:39 +01:00
void init_maze_old(t_maze maze[NXMAZE*NYMAZE])
2022-10-18 23:28:20 +02:00
/* init a maze */
{
2022-11-20 23:17:39 +01:00
int i, pathlength, *path;
2022-10-18 23:28:20 +02:00
init_maze_graph(maze);
for (i=0; i<RAND_SHIFT; i++) rand();
2022-11-20 23:17:39 +01:00
for (i=0; i<NXMAZE*NYMAZE; i++) if (!maze[i].tested) find_maze_path(maze, i, path, &pathlength);
2022-10-18 23:28:20 +02:00
}
2022-11-20 23:17:39 +01:00
void init_maze(t_maze maze[NXMAZE*NYMAZE])
/* init a maze with exit at (nx, ny) */
{
int i, j, n, deadend, pathlength, newpathlength;
int *path, *newpath;
path = (int *)malloc(2*NXMAZE*NYMAZE*sizeof(short int));
newpath = (int *)malloc(2*NXMAZE*NYMAZE*sizeof(short int));
init_maze_graph(maze);
for (i=0; i<RAND_SHIFT; i++) rand();
find_maze_path(maze, 0, path, &pathlength);
for (n=0; n<pathlength; n++) maze[path[n]].connected = 1;
for (i=0; i<NXMAZE*NYMAZE; i++) if ((!maze[i].tested)&&(!maze[i].connected))
{
deadend = find_maze_path(maze, i, path, &pathlength);
if (!deadend) for (n=0; n<pathlength; n++) maze[path[n]].connected = 1;
j = 0;
printf("deadend = %i, pathlength = %i\n", deadend, pathlength);
// while ((deadend)&&(j < pathlength))
while (deadend)
{
j++;
if (j > pathlength) j = 0;
printf("j = %i\n", j);
// while (deadend)
if (!maze[path[j]].connected) deadend = find_maze_path(maze, path[j], newpath, &newpathlength);
if (!deadend) for (n=0; n<newpathlength; n++) maze[newpath[n]].connected = 1;
}
// for (n=0; n<newpathlength; n++) maze[newpath[n]].connected = 1;
for (j=0; j<NXMAZE*NYMAZE; j++) if (maze[j].tested) maze[j].connected = 1;
}
free(path);
free(newpath);
}
void init_maze_exit(int nx, int ny, t_maze maze[NXMAZE*NYMAZE])
/* init a maze with exit at (nx, ny) */
{
int i, j, n, deadend, pathlength, newpathlength;
int *path, *newpath;
path = (int *)malloc(2*NXMAZE*NYMAZE*sizeof(short int));
newpath = (int *)malloc(2*NXMAZE*NYMAZE*sizeof(short int));
init_maze_graph(maze);
for (i=0; i<RAND_SHIFT; i++) rand();
find_maze_path(maze, nmaze(nx, ny), path, &pathlength);
for (n=0; n<pathlength; n++) maze[path[n]].connected = 1;
for (i=0; i<NXMAZE*NYMAZE; i++) if ((!maze[i].tested)&&(!maze[i].connected))
{
deadend = find_maze_path(maze, i, path, &pathlength);
if (!deadend) for (n=0; n<pathlength; n++) maze[path[n]].connected = 1;
j = 0;
printf("deadend = %i, pathlength = %i\n", deadend, pathlength);
// while ((deadend)&&(j < pathlength))
while (deadend)
{
j++;
if (j > pathlength) j = 0;
printf("j = %i\n", j);
// while (deadend)
if (!maze[path[j]].connected) deadend = find_maze_path(maze, path[j], newpath, &newpathlength);
if (!deadend) for (n=0; n<newpathlength; n++) maze[newpath[n]].connected = 1;
}
// for (n=0; n<newpathlength; n++) maze[newpath[n]].connected = 1;
for (j=0; j<NXMAZE*NYMAZE; j++) if (maze[j].tested) maze[j].connected = 1;
}
free(path);
free(newpath);
}
2022-10-18 23:28:20 +02:00