Use generic PQ

This commit is contained in:
2022-01-17 14:11:52 -05:00
parent 0272fd726d
commit 05d5cf3d79
3 changed files with 130 additions and 139 deletions

View File

@@ -2,42 +2,57 @@
#include "prim.h"
#include "set.h"
typedef struct {
size_t x, y;
mazeedge_dir_t dir;
} _point_t;
DEFINE_PQ(_point_t, PointPQ, unsigned int);
void prim(mazegrid_t const* g, mazegrid_t* result) {
struct pq* q = pq_new(g->width*g->height*4);
NEW_PQ_SZ(PointPQ, q, g->width*g->height*4);
struct node_set* s = node_set_new(g->width, g->height);
*result = mazegrid_new(g->width, g->height);
node_set_add(s, 0, 0);
if (g->height > 1) pq_add(q, mazegrid_get_edge(g, 0, 0, EDGE_UP), 0, 1, EDGE_DOWN);
if (g->width > 1) pq_add(q, mazegrid_get_edge(g, 0, 0, EDGE_RIGHT), 1, 0, EDGE_LEFT);
while (!pq_empty(q) && (node_set_size(s) < g->width * g->height)) {
size_t x, y;
mazeedge_dir_t dir;
pq_pop(q, &x, &y, &dir);
if (node_set_contains(s, x, y)) continue;
if (g->height > 1) {
_point_t e = { 0, 1, EDGE_DOWN };
PUSH_PQ(q, PointPQ, e, mazegrid_get_edge(g, 0, 0, EDGE_UP));
}
if (g->width > 1) {
_point_t e = { 1, 0, EDGE_LEFT };
PUSH_PQ(q, PointPQ, e, mazegrid_get_edge(g, 0, 0, EDGE_RIGHT));
}
while (!EMPTY_PQ(q) && (node_set_size(s) < g->width * g->height)) {
_point_t e;
unsigned int p;
POP_PQ(q, PointPQ, e, p);
if (node_set_contains(s, e.x, e.y)) continue;
// add edge to tree
mazegrid_set_edge(result, x, y, dir, 1);
mazegrid_set_edge(result, e.x, e.y, e.dir, 1);
// add neighbors
if ((x > 0) && !node_set_contains(s, x - 1, y)) {
pq_add(q, mazegrid_get_edge(g, x, y, EDGE_LEFT), x - 1, y, EDGE_RIGHT);
if ((e.x > 0) && !node_set_contains(s, e.x - 1, e.y)) {
_point_t pt = { e.x - 1, e.y, EDGE_RIGHT };
PUSH_PQ(q, PointPQ, pt, mazegrid_get_edge(g, e.x, e.y, EDGE_LEFT));
}
if ((x < g->width - 1) && !node_set_contains(s, x + 1, y)) {
pq_add(q, mazegrid_get_edge(g, x, y, EDGE_RIGHT), x + 1, y, EDGE_LEFT);
if ((e.x < g->width - 1) && !node_set_contains(s, e.x + 1, e.y)) {
_point_t pt = { e.x + 1, e.y, EDGE_LEFT };
PUSH_PQ(q, PointPQ, pt, mazegrid_get_edge(g, e.x, e.y, EDGE_LEFT));
}
if ((y > 0) && !node_set_contains(s, x, y - 1)) {
pq_add(q, mazegrid_get_edge(g, x, y, EDGE_DOWN), x, y - 1, EDGE_UP);
if ((e.y > 0) && !node_set_contains(s, e.x, e.y - 1)) {
_point_t pt = { e.x, e.y - 1, EDGE_UP };
PUSH_PQ(q, PointPQ, pt, mazegrid_get_edge(g, e.x, e.y, EDGE_DOWN));
}
if ((y < g->height - 1) && !node_set_contains(s, x, y + 1)) {
pq_add(q, mazegrid_get_edge(g, x, y, EDGE_UP), x, y + 1, EDGE_DOWN);
if ((e.y < g->height - 1) && !node_set_contains(s, e.x, e.y + 1)) {
_point_t pt = { e.x, e.y + 1, EDGE_DOWN };
PUSH_PQ(q, PointPQ, pt, mazegrid_get_edge(g, e.x, e.y, EDGE_UP));
}
node_set_add(s, x, y);
node_set_add(s, e.x, e.y);
}
node_set_free(s);
pq_free(q);
FREE_PQ(q);
}