Sidewinder maze instead of dfs

This commit is contained in:
Carlos Sanchez 2024-08-22 01:41:18 -04:00
parent 4fdd6f95e9
commit 6eaf0d9961

101
maze.c
View File

@ -34,6 +34,13 @@
#define MAZEENDGAP (MAZESIZE / 5)
#define HSCALE 1.5
#define PAINTINGODDS 20
// Some arbitrarily large number, up to you
#define MAZEHRAND 100
// The horizontal choice will be this out of MAZEHRAND.
// So, if MAZEHRAND is 100, setting this to 80 will mean
// an 8 / 10 chance to go horizontal
#define MAZEHBIAS 60
#define PRINTMAZE
// Maze grows in the positive direction
#define MAZENORTH 1
@ -157,69 +164,29 @@ void maze_generate(uint8_t *maze, int size, struct vec2i *start,
for (int i = 0; i < mazesquare; i++) {
maze[i] = MAZENORTH | MAZEEAST;
}
int *mazestack;
mallocordie(mazestack, sizeof(int) * mazesquare);
for (int i = 0; i < size * size; i++) {
mazestack[i] = -1;
}
// Push current cell onto stack, mark as visited
start->x = rand() % size;
start->y = rand() % size;
int x = start->x;
int y = start->y;
int mazetop = 0;
int maxmazetop = 0;
STACKPUSH(mazestack, mazetop, x + y * size);
maze[x + y * size] |= MAZEVISIT;
uint8_t visitable[4];
int visittop = 0;
// Now let's make a maze!
while (mazetop) {
// The end of the maze is the furthest into the stack we go. This should
// somewhat maximize the complexity of start to finish?
if (mazetop > maxmazetop) {
// end->x = x;
// end->y = y;
maxmazetop = mazetop;
}
mazetop--;
visittop = 0;
x = mazestack[mazetop] % size;
y = mazestack[mazetop] / size;
if (x > 0 && !maze_visited(maze, x - 1, y, size)) {
visitable[visittop++] = DIRWEST;
}
if (x < size - 1 && !maze_visited(maze, x + 1, y, size)) {
visitable[visittop++] = DIREAST;
}
if (y > 0 && !maze_visited(maze, x, y - 1, size)) {
visitable[visittop++] = DIRSOUTH;
}
if (y < size - 1 && !maze_visited(maze, x, y + 1, size)) {
visitable[visittop++] = DIRNORTH;
}
// You can generate a random location!
if (visittop) {
// Readd ourselves, we're moving
STACKPUSH(mazestack, mazetop, x + y * size);
uint8_t dir = visitable[rand() % visittop];
struct vec2i movedir = dirtovec(dir);
int nx = x + movedir.x;
int ny = y + movedir.y;
// Trust that the visitable array is always valid
if (dir == DIREAST) { // Tear down east wall
// Extremely simple sidewinder algorithm. Because the maze grows northeast, we
// actually have to start from the end and work backwards
for (int y = size - 1; y >= 0; y--) {
if (y == size - 1) {
for (int x = 0; x < size - 1; x++) {
maze[x + y * size] &= ~MAZEEAST;
}
continue;
}
int xs = 0;
for (int x = 0; x < size; x++) {
// If we decide to stop (or it's the end), find a place in our
// current span to carve north
if ((x == size - 1) || ((rand() % MAZEHRAND) > MAZEHBIAS)) {
maze[xs + (rand() % (x - xs + 1)) + y * size] &= ~MAZENORTH;
xs = x + 1;
} else {
maze[x + y * size] &= ~MAZEEAST;
} else if (dir == DIRWEST) { // Move left and tear down east wall
maze[(x - 1) + y * size] &= ~MAZEEAST;
} else if (dir == DIRNORTH) { // tear down north wall
maze[x + y * size] &= ~MAZENORTH;
} else if (dir == DIRSOUTH) { // move down and tear down north wall
maze[x + (y - 1) * size] &= ~MAZENORTH;
}
// Push onto stack and set visited
STACKPUSH(mazestack, mazetop, nx + ny * size);
maze[nx + ny * size] |= MAZEVISIT;
}
}
@ -229,10 +196,22 @@ void maze_generate(uint8_t *maze, int size, struct vec2i *start,
} while (abs(end->x - start->x) < MAZEENDGAP &&
abs(end->y - start->y) < MAZEENDGAP);
eprintf("Maze generate: %d,%d -> %d,%d maxdepth: %d\n", start->x, start->y,
end->x, end->y, maxmazetop);
#ifdef PRINTMAZE
char line[MAZESIZE * 4]; // IDK, just in case
// -1 because we draw the top line
for (int y = -1; y < size; y++) {
for (int x = size - 1; x >= 0; x--) {
line[x * 2] = (y == -1 || maze[x + y * size] & MAZENORTH) ? '_' : ' ';
line[x * 2 + 1] =
(y == -1 || (maze[x + y * size] & MAZEEAST) == 0) ? ' ' : '|';
}
line[size * 2] = 0;
eprintf("|%s\n", line);
}
#endif
free(mazestack);
eprintf("Maze generate: %d,%d -> %d,%d\n", start->x, start->y, end->x,
end->y);
}
// int rand_painting(int size) {