diff --git a/include/mazemaker.h b/include/mazemaker.h index 883f814..fc295f4 100644 --- a/include/mazemaker.h +++ b/include/mazemaker.h @@ -22,6 +22,15 @@ typedef enum { EDGE_LEFT } mazeedge_dir_t; +typedef struct { + size_t x, y; +} maze_point_t; + +typedef struct { + size_t length; + maze_point_t* nodes; +} maze_path_t; + typedef struct mazeoptions mazeoptions_t; void mazemaker_generate_maze(int width, int height, mazegrid_t* result); @@ -38,4 +47,7 @@ int mazemaker_options_set_wall_color(mazeoptions_t*, char const* color_desc); int mazemaker_options_set_background_color(mazeoptions_t*, char const* color_desc); void mazemaker_options_set_seed(mazeoptions_t*, unsigned int seed); +int mazemaker_solve(mazegrid_t const* maze, maze_path_t* path); +void mazemaker_path_free(maze_path_t* path); + #endif // !def(_MAZEMAKER_H) diff --git a/lib/path.c b/lib/path.c new file mode 100644 index 0000000..e990d9f --- /dev/null +++ b/lib/path.c @@ -0,0 +1,109 @@ +#include +#include +#include "pq.h" +#include "set.h" + +DEFINE_PQ(maze_path_t, PathPQ, unsigned int); + +static void path_copy(maze_path_t const* src, maze_path_t* dst) { + dst->length = src->length; + dst->nodes = calloc(dst->length, sizeof(maze_point_t)); + memcpy(dst->nodes, src->nodes, src->length * sizeof(maze_point_t)); +} + +static void path_copy_append(maze_path_t const* src, maze_path_t* dst, maze_point_t pt) { + dst->length = src->length + 1; + dst->nodes = calloc(dst->length, sizeof(maze_point_t)); + memcpy(dst->nodes, src->nodes, src->length * sizeof(maze_point_t)); + dst->nodes[dst->length - 1] = pt; +} + +int mazemaker_solve(mazegrid_t const* maze, maze_path_t* path) { + int code = 0; + struct node_set* set = node_set_new(maze->width, maze->height); + NEW_PQ(PathPQ, pq); + + // put starting point in the queue + maze_path_t start; + start.length = 1; + start.nodes = malloc(sizeof(maze_point_t)); + start.nodes[0].x = 0; + start.nodes[0].y = 0; + + PUSH_PQ(pq, PathPQ, start, 0); + while (!EMPTY_PQ(pq)) { + maze_path_t top; + unsigned int dist; + size_t x, y; + POP_PQ(pq, PathPQ, top, dist); + + x = top.nodes[top.length - 1].x; + y = top.nodes[top.length - 1].y; + node_set_add(set, x, y); + + // check to see if we've reached the end + if ((x == maze->width - 1) && (y == maze->height - 1)) { + path_copy(&top, path); + code = 1; + break; + } + + // otherwise check for unexplored paths in all directions... + + // ... up + if ((y < maze->height) && (mazegrid_get_edge(maze, x, y, EDGE_UP) != 0)) { + if (!node_set_contains(set, x, y + 1)) { + maze_path_t newpath; + maze_point_t pt = { .x = x, .y = y + 1 }; + path_copy_append(&top, &newpath, pt); + PUSH_PQ(pq, PathPQ, newpath, dist + 1); + } + } + + // ... right + if ((x < maze->width) && (mazegrid_get_edge(maze, x, y, EDGE_RIGHT) != 0)) { + if (!node_set_contains(set, x + 1, y)) { + maze_path_t newpath; + maze_point_t pt = { .x = x + 1, .y = y }; + path_copy_append(&top, &newpath, pt); + PUSH_PQ(pq, PathPQ, newpath, dist + 1); + } + } + + // ... down + if ((y > 0) && (mazegrid_get_edge(maze, x, y, EDGE_DOWN) != 0)) { + if (!node_set_contains(set, x, y - 1)) { + maze_path_t newpath; + maze_point_t pt = { .x = x, .y = y - 1}; + path_copy_append(&top, &newpath, pt); + PUSH_PQ(pq, PathPQ, newpath, dist + 1); + } + } + + // ... left + if ((x > 0) && (mazegrid_get_edge(maze, x, y, EDGE_LEFT) != 0)) { + if (!node_set_contains(set, x - 1, y)) { + maze_path_t newpath; + maze_point_t pt = { .x = x - 1, .y = y }; + path_copy_append(&top, &newpath, pt); + PUSH_PQ(pq, PathPQ, newpath, dist + 1); + } + } + } + + // If no path is found, we will run out of new nodes to explore, the queue + // will go empty, and the loop will terminate. The default return code of 0 + // indicates that no solution has been put in the path parameter. + + if (!EMPTY_PQ(pq)) { + maze_path_t top; + unsigned int dist; + FOREACH_PQ(pq, top, dist) { + free(top.nodes); + } + FOREACH_PQ_END + } + node_set_free(set); + return code; +} + diff --git a/lib/path.h b/lib/path.h deleted file mode 100644 index b7bc19c..0000000 --- a/lib/path.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef _PATH_H -#define _PATH_H 1 - -#include "grid.h" - -typedef struct { - unsigned row, col; -} block_t; - -typedef struct { - size_t length; - block_t *nodes; -} path_t; - -int shortest_path(mazegrid_t const* maze, path_t* result); -void free_path(path_t* p); - -#endif // !def(_PATH_H)