Optimize Dijkstra's inner loop for hex maps

Because the cost to enter a sector is independent of the direction of
entry, we visit sectors at most once.  Exploit that.

Beware: this is not the case for A*.  Pitfall for any future
generalization to A*.

Speeds up distribution path assembly by 35-40% in my tests.
This commit is contained in:
Markus Armbruster 2011-02-26 17:40:13 +01:00
parent ffbbfcb25f
commit d7dccef3b1

View file

@ -112,12 +112,14 @@ static int pf_suid;
static natid pf_actor; static natid pf_actor;
static double (*pf_sct_cost)(natid, int); static double (*pf_sct_cost)(natid, int);
#ifndef NDEBUG /* silence "not used" warning */
/* Is sector with uid UID open? */ /* Is sector with uid UID open? */
static int static int
pf_is_open(int uid) pf_is_open(int uid)
{ {
return pf_map[uid].visit == pf_visit; return pf_map[uid].visit == pf_visit;
} }
#endif
/* Is sector with uid UID closed? */ /* Is sector with uid UID closed? */
static int static int
@ -222,21 +224,16 @@ pf_open(int uid, coord x, coord y, int dir, double cost)
{ {
int i; int i;
if (pf_is_open(uid)) {
i = pf_map[uid].heapi;
DPRINTF("pf: reopen %d,%d %g %c %d\n", x, y, cost, dirch[dir], i);
assert(cost < pf_map[uid].cost);
} else {
i = pf_nheap++; i = pf_nheap++;
DPRINTF("pf: open %d,%d %g %c %d\n", x, y, cost, dirch[dir], i); DPRINTF("pf: open %d,%d %g %c %d\n", x, y, cost, dirch[dir], i);
pf_map[uid].heapi = i; assert(pf_is_unvisited(uid));
pf_map[uid].visit = pf_visit; pf_map[uid].visit = pf_visit;
pf_map[uid].dir = dir;
pf_map[uid].heapi = i;
pf_map[uid].cost = cost;
pf_heap[i].uid = uid; pf_heap[i].uid = uid;
pf_heap[i].x = x; pf_heap[i].x = x;
pf_heap[i].y = y; pf_heap[i].y = y;
}
pf_map[uid].dir = dir;
pf_map[uid].cost = cost;
pf_heap[i].cost = cost; pf_heap[i].cost = cost;
pf_sift_up(i); pf_sift_up(i);
@ -359,10 +356,18 @@ path_find_to(coord dx, coord dy)
nx = x_in_dir(x, DIR_FIRST + i); nx = x_in_dir(x, DIR_FIRST + i);
ny = y_in_dir(y, DIR_FIRST + i); ny = y_in_dir(y, DIR_FIRST + i);
nuid = XYOFFSET(nx, ny); nuid = XYOFFSET(nx, ny);
/*
* Cost to enter NX,NY doesn't depend on direction of
* entry. This X,Y is at least as expensive as any
* previous one. Therefore, cost to go to NX,NY via X,Y
* is at least as high as any previously found route.
* Skip neighbors that have a route already.
*/
if (!pf_is_unvisited(nuid))
continue;
c1 = pf_sct_cost(pf_actor, nuid); c1 = pf_sct_cost(pf_actor, nuid);
if (c1 < 0) if (c1 < 0)
continue; continue;
if (pf_is_unvisited(nuid) || cost + c1 < pf_map[nuid].cost)
pf_open(nuid, nx, ny, DIR_FIRST + i, cost + c1); pf_open(nuid, nx, ny, DIR_FIRST + i, cost + c1);
} }
} }