Skip to content

Commit

Permalink
Implement explicit stack, animated generation, woohoo wahey!
Browse files Browse the repository at this point in the history
  • Loading branch information
nok-ko committed Apr 10, 2022
1 parent 4e9512e commit e7ad387
Show file tree
Hide file tree
Showing 5 changed files with 194 additions and 48 deletions.
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ endif()

set(CMAKE_C_STANDARD 11) # Requires C11 standard

add_library(stack stack.c)
add_library(maze_gen maze.c)
add_executable(ray_maze main.c)

target_link_libraries(ray_maze raylib maze_gen)
target_link_libraries(ray_maze raylib maze_gen stack)

# Checks if OSX and links appropriate frameworks (only required on MacOS)
if (APPLE)
Expand Down
21 changes: 17 additions & 4 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,23 +44,36 @@ int main(void) {
// Generate maze;
const int sideLength = 30;
int *box_data = (int *) calloc(sideLength*sideLength, sizeof(int));
maze_t box_maze = {box_data,sideLength,sideLength};
carve_maze(&box_maze);
maze_t m = {box_data, sideLength, sideLength};
fill_maze(&m);
carve_maze(&m);

unsigned int frames = 0;
size_t initial_cap = (m.width * m.height) / 4;
arr_stack_t *stack = new_stack(sizeof(pos_t), initial_cap);
pos_t current = {0, 0};
while (!WindowShouldClose()) {
BeginDrawing();
{
if (frames % 2 == 0 && stack->len > 0) {
carve_step(&m, stack, &current);
}
ClearBackground(RAYWHITE);
DrawText("RayMaze!", screen_width - 30, 30, 20, LIGHTGRAY);
draw_maze(&box_maze, 10, 10, 9);
draw_maze(&m, 10, 10, 9);
DrawRectangle(10 + (9 * current.ox) + 3, 10 + (9 * current.oy) + 3, 3, 3, MAGENTA);
if (IsMouseButtonReleased(MOUSE_BUTTON_LEFT)) {
carve_maze(&box_maze);
current = (pos_t) {0, 0};
fill_maze(&m);
push(stack, &current);
}
frames++;
}
EndDrawing();
}

CloseWindow();
free(box_data);
free_stack(stack);
return 0;
}
131 changes: 88 additions & 43 deletions maze.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Credit to Jamis Buck for teaching me this wonderful algorithm.
#include <stdlib.h>
#include <stdbool.h>
#include "maze.h"
#include "stack.h"

// Fill a maze with walls, i.e. NONE values
void fill_maze(struct maze *m) {
Expand All @@ -24,49 +25,39 @@ void fill_maze(struct maze *m) {
}

// get a random neighbour!
struct neighbour get_neighbour(int ox, int oy, struct maze *m) {
// check out-of-bounds
bool can_N, can_E, can_S, can_W;
can_N = (oy - 1) >= 0;
can_E = (ox + 1) < m->width;
can_S = (oy + 1) < m->height;
can_W = (ox - 1) >= 0;

struct neighbour neighbours[4];
neighbour_t get_neighbour(int ox, int oy, struct maze *m) {
typedef struct {
int direction;
char offset_x;
char offset_y;
bool isNotOOB;
} direction_t;

direction_t directions[4] = {
N, 0, -1, (oy - 1) >= 0,
E, 1, 0, (ox + 1) < m->width,
S, 0, 1, (oy + 1) < m->height,
W, -1, 0, (ox - 1) >= 0,
};

neighbour_t neighbours[4];
int count = 0;
// North: (0, -1)
if (can_N) {
int *data = &m->data[(m->width * (oy - 1)) + (ox)];
if (*data == NONE) {
neighbours[count] = (struct neighbour) {0, -1, N, data};
count++;
}
}
// East: (+1, 0)
if (can_E) {
int *data = &m->data[(m->width * (oy)) + (ox + 1)];
if (*data == NONE) {
neighbours[count] = (struct neighbour) {1, 0, E, data};
count++;
}
}
// South: (0, +1)
if (can_S) {
int *data = &m->data[(m->width * (oy + 1)) + (ox)];
if (*data == NONE) {
neighbours[count] = (struct neighbour) {0, 1, S, data};
count++;
}
}
// West: (-1, 0)
if (can_W) {
int *data = &m->data[(m->width * (oy)) + (ox - 1)];
if (*data == NONE) {
neighbours[count] = (struct neighbour) {-1, 0, W, data};
count++;
for (int i = 0; i < 4; i++) {
const direction_t current = directions[i];
if (current.isNotOOB) {
int *data = &m->data[(m->width * (oy + current.offset_y)) + (ox + current.offset_x)];
if (*data == NONE) {
neighbours[count] = (neighbour_t) {
current.offset_x,
current.offset_y,
current.direction,
data
};
count++;
}
}
}
struct neighbour out = {.ox=0, .oy=0};
neighbour_t out = {.ox=0, .oy=0};
// No valid neighbours.
if (count == 0) {
// Can't keep going, return!
Expand All @@ -77,8 +68,7 @@ struct neighbour get_neighbour(int ox, int oy, struct maze *m) {
// Honestly, I've stopped caring.
// PRO TIP: MAKE SURE YOU DON'T INDEX BY NEGATIVE VALUES.
// THIS BUG TOOK AWAY VALUABLE HOURS OF MY LIFE.
int rand = arc4random();
out = neighbours[rand % count];
out = neighbours[arc4random() % count];
return out;
}

Expand All @@ -99,6 +89,10 @@ static const int opposite[N+1] = {
S
};

typedef struct {int ox; int oy;} pos_t;

void carve_step(struct maze *m, arr_stack_t *stack, pos_t *current);

void carve(int ox, int oy, struct maze *m) {
int *current = &m->data[(m->width * oy) + ox];
while (true) {
Expand All @@ -122,10 +116,61 @@ void carve(int ox, int oy, struct maze *m) {
}
}


void carve_iter(int ox, int oy, struct maze *m) {
size_t initial_cap = (m->width * m->height) / 4;
arr_stack_t *stack = new_stack(sizeof(pos_t), initial_cap);
pos_t current = {ox, oy};
push(stack, &current);
while (stack->len) {
carve_step(m, stack, &current);
}
free_stack(stack);
}

void carve_step(struct maze *m, arr_stack_t *stack, pos_t *current) {
int *cell = &m->data[(m->width * (*current).oy) + (*current).ox];
neighbour_t nb = get_neighbour((*current).ox, (*current).oy, m);
// no neighbours here, move on
if (nb.ox != 0 || nb.oy != 0) {
// Check if there's any path to the neighbour
// If not:
if (!(*cell & nb.direction) && *nb.data == NONE) {
*nb.data |= opposite[nb.direction]; // carved!
// carve self!
*cell |= nb.direction;
// recur!
push(stack, &((pos_t) {current->ox + nb.ox, current->oy + nb.oy}));
peek(stack, current);
}
} else {
pop(stack, current);
}
}
void carve_step_fishbone(struct maze *m, arr_stack_t *stack, pos_t *current) {
int *cell = &m->data[(m->width * (*current).oy) + (*current).ox];
neighbour_t nb = get_neighbour((*current).ox, (*current).oy, m);
// no neighbours here, move on
if (nb.ox != 0 || nb.oy != 0) {
// Check if there's any path to the neighbour
// If not:
if (!(*cell & nb.direction) && *nb.data == NONE) {
*nb.data |= opposite[nb.direction]; // carved!
// carve self!
*cell |= nb.direction;
// recur!
push(stack, &((pos_t) {current->ox + nb.ox, current->oy + nb.oy}));
// peek(stack, current);
}
} else {
pop(stack, current);
}
}

void carve_maze(maze_t *m) {
// Fill the maze, we'll be carving paths out.
fill_maze(m);
carve(0, 0, m);
carve_iter(0, 0, m);
}

//int main(int argc, char **argv) {
Expand Down
59 changes: 59 additions & 0 deletions stack.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
//
// Created by Nokko on 2022-04-09.
//

#include <stdlib.h>
#include <string.h>

typedef struct {
size_t len; // # elements
size_t cap; // capacity
size_t element_size;
void *data;
} arr_stack_t;

arr_stack_t *new_stack(size_t element_size, size_t initial_cap) {
arr_stack_t *stack = (arr_stack_t *) calloc(1,sizeof (arr_stack_t));
if (stack == NULL) return NULL;
stack->data = malloc(element_size * initial_cap);
if (stack->data == NULL) {
free(stack);
return NULL;
}
stack->element_size = element_size;
stack->cap = initial_cap;
return stack;
}

void free_stack(arr_stack_t *stack) {
free(stack->data);
free(stack);
}

void realloc_stack(arr_stack_t *stack) {
size_t new_cap = (stack->element_size * stack->len) * 2;
void *new_data = realloc(stack->data, new_cap);
stack->data = new_data;
stack->cap = new_cap;
}

size_t push(arr_stack_t *stack, void *data) {
stack->len += 1;
if (stack->len > stack->cap) {
realloc_stack(stack);
}
memcpy(stack->data + (stack->len - 1) * stack->element_size, data, stack->element_size);
return stack->len;
}

size_t peek(arr_stack_t *stack, void *dest) {
if ((stack->len - 1) < 0) return 0;
memcpy(dest, stack->data + (stack->len - 1) * stack->element_size, stack->element_size);
return stack->len;
}

size_t pop(arr_stack_t *stack, void *dest) {
if ((stack->len - 1) < 0) return 0;
memcpy(dest, stack->data + (--stack->len) * stack->element_size, stack->element_size);
return stack->len;
}
28 changes: 28 additions & 0 deletions stack.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// Created by Nokko on 2022-04-09.
//

#include <stdlib.h>
#ifndef RAY_MAZE_STACK_H
#define RAY_MAZE_STACK_H

typedef struct {
size_t len; // # elements
size_t cap; // capacity
size_t element_size;
void *data;
} arr_stack_t;

arr_stack_t *new_stack(size_t element_size, size_t initial_cap);

void free_stack(arr_stack_t *stack);

void realloc_stack(arr_stack_t *stack);

size_t push(arr_stack_t *stack, void *data);

size_t pop(arr_stack_t *stack, void *dest);

size_t peek(arr_stack_t *stack, void *dest);

#endif //RAY_MAZE_STACK_H

0 comments on commit e7ad387

Please sign in to comment.