diff --git a/jps.hh b/jps.hh index 6a76d86..757dd52 100644 --- a/jps.hh +++ b/jps.hh @@ -283,6 +283,9 @@ enum JPS_Flags_ // Don't check whether end position is walkable. JPS_Flag_NoEndCheck = 0x08, + + // Find closest path + JPS_Flag_Closest = 0x16, }; enum JPS_Result @@ -896,6 +899,8 @@ public: private: const GRID& grid; + Position closestPosition; + ScoreType closestBestDistance; Node *getNode(const Position& pos); bool identifySuccessors(const Node& n); @@ -1291,9 +1296,18 @@ template template bool Searcher::findPath(PV& case JPS_EMPTY_PATH: JPS_ASSERT(false); // can't happen // fall through - case JPS_NO_PATH: case JPS_OUT_OF_MEMORY: return false; + case JPS_NO_PATH: + if(flags & JPS_Flag_Closest) + { + if (start != closestPosition) + { + endNodeIdx = storage.getindex(getNode(closestPosition)); + return findPathFinish(path, step) == JPS_FOUND_PATH; + } + } + return false; } } } @@ -1305,6 +1319,8 @@ template JPS_Result Searcher::findPathInit(Position start, this->flags = flags; endPos = end; + closestBestDistance = UINT_MAX; + closestPosition = start; // FIXME: check this if(start == end && !(flags & (JPS_Flag_NoStartCheck|JPS_Flag_NoEndCheck))) @@ -1318,11 +1334,15 @@ template JPS_Result Searcher::findPathInit(Position start, if(!grid(start.x, start.y)) return JPS_NO_PATH; - if(!(flags & JPS_Flag_NoEndCheck)) + if(!(flags & (JPS_Flag_NoEndCheck | JPS_Flag_Closest))) if(!grid(end.x, end.y)) return JPS_NO_PATH; - Node *endNode = getNode(end); // this might realloc the internal storage... + Node *endNode = NULL; + if(flags & JPS_Flag_NoEndCheck) + endNode = nodemap(end.x, end.y); + else + endNode = getNode(end); // this might realloc the internal storage... if(!endNode) return JPS_OUT_OF_MEMORY; endNodeIdx = storage.getindex(endNode); // .. so we keep this for later @@ -1353,6 +1373,23 @@ template JPS_Result Searcher::findPathStep(int limit) return JPS_NO_PATH; Node& n = open.popNode(); n.setClosed(); + if(flags & JPS_Flag_Closest) + { + if(closestBestDistance == M_MAX_UNSIGNED) + { + closestPosition = n.pos; + closestBestDistance = Heuristic::Manhattan(n.pos, endPos); + } + else + { + unsigned h = Heuristic::Manhattan(n.pos, endPos); + if(closestBestDistance > h) + { + closestBestDistance = h; + closestPosition = n.pos; + } + } + } if(n.pos == endPos) return JPS_FOUND_PATH; if(!identifySuccessors(n))