ref: 71250575dc797b28a5e9a9e8fd612c1253be9bc1
parent: c9f95c308362fed2f2d9cb5a309b1ed0338594e6
author: qwx <qwx@sciops.net>
date: Wed Mar 23 18:07:11 EDT 2022
implement dijkstra search
--- a/path/dat.h
+++ b/path/dat.h
@@ -11,6 +11,7 @@
int closed;
double g;
double h;
+ double Δg;
Node *to;
Node *from;
Pairheap *pq;
--- a/path/dijkstra.c
+++ b/path/dijkstra.c
@@ -10,19 +10,99 @@
Node *start, *goal;
-static int
-dijkstra(Node *a, Node *g)
+static void
+backtrack(void)
{
- USED(a,g);
- return 0;
+ Node *n;
+
+ assert(goal != start);
+ for(n=goal; n!=start; n=n->from)
+ n->from->to = n;
}
+static Node **
+successors(Node *n)
+{
+ static Node *suc[8+1];
+ static dtab[2*(nelem(suc)-1)]={
+ -1,-1, 0,-1, 1,-1,
+ -1,0, 1,0,
+ -1,1, 0,1, 1,1,
+ };
+ int i;
+ Node *s, **np;
+ Point p;
+ Rectangle r;
+
+ memset(suc, 0, sizeof suc);
+ p = n2p(n);
+ r = Rect(0, 0, mapwidth, mapheight);
+ for(i=0, np=suc; i<nelem(dtab); i+=2){
+ if(!ptinrect(addpt(p, Pt(dtab[i], dtab[i+1])), r))
+ continue;
+ s = n + dtab[i+1] * mapwidth + dtab[i];
+ assert(s >= map && s < map + mapwidth * mapheight);
+ if(isblocked(s))
+ continue;
+ s->Δg = dtab[i] != 0 && dtab[i+1] != 0 ? SQRT2 : 1;
+ *np++ = s;
+ }
+ return suc;
+}
+
+static Node *
+dijkstra(Node *a, Node *b)
+{
+ double g, Δg;
+ Node *x, *s, **sl;
+ Pairheap *queue, *pn;
+
+ assert(a != nil && b != nil);
+ assert(a != b);
+ queue = nil;
+ x = a;
+ a->pq = pushqueue(0, a, &queue);
+ while((pn = popqueue(&queue)) != nil){
+ x = pn->aux;
+ free(pn);
+ if(x == b)
+ break;
+ x->closed = 1;
+ if((sl = successors(x)) == nil)
+ sysfatal("a∗: %r");
+ for(s=*sl++; s!=nil; s=*sl++){
+ if(s->closed)
+ continue;
+ assert(!isblocked(s));
+ g = x->g + s->Δg;
+ Δg = s->g - g;
+ if(!s->open){
+ s->from = x;
+ s->open = 1;
+ s->g = g;
+ s->pq = pushqueue(s->g, s, &queue);
+ }else if(Δg > 0){
+ s->from = x;
+ s->g -= Δg;
+ decreasekey(s->pq, Δg, &queue);
+ assert(s->g >= 0);
+ }
+ }
+ }
+ nukequeue(&queue);
+ return x;
+}
+
static int
findpath(void)
{
if(start == nil || goal == nil)
return -1;
- return dijkstra(start, goal);
+ resetmap();
+ if(dijkstra(start, goal) != goal)
+ return -1;
+ backtrack();
+ return 0;
}
int
@@ -29,8 +109,8 @@
mouseinput(Node *n, Mouse m)
{
switch(m.buttons & 7){
- case 1: goal = n; findpath(); break;
- case 2: start = n; findpath(); break;
+ case 1: if(start != n) goal = n; return findpath();
+ case 2: if(goal != n) start = n; return findpath();
case 4: n->blocked ^= 1; break;
}
return 0;