mirror of
https://github.com/glest/glest-source.git
synced 2025-02-25 12:12:25 +01:00
* path finding into unexplored areas handled more intelligently (and without revealing/exploiting information the player shouldn't have)
This commit is contained in:
parent
ecc78d24bd
commit
20165b4566
@ -131,9 +131,10 @@ bool RoutePlanner::isLegalMove(Unit *unit, const Vec2i &pos2) const {
|
||||
assert(unit->getPos().dist(pos2) < 1.5);
|
||||
|
||||
float d = unit->getPos().dist(pos2);
|
||||
if (d > 1.5 || d < 0.9f) {
|
||||
throw runtime_error("The new Pathfinder lied.");
|
||||
}
|
||||
//if (d > 1.6 || d < 0.7f) {
|
||||
// printf("\nd = %g", d);
|
||||
// throw runtime_error("The new Pathfinder lied.");
|
||||
//}
|
||||
|
||||
const Vec2i &pos1 = unit->getPos();
|
||||
const int &size = unit->getType()->getSize();
|
||||
@ -207,15 +208,14 @@ float RoutePlanner::quickSearch(Field field, int size, const Vec2i &start, const
|
||||
return -1.f;
|
||||
}
|
||||
|
||||
HAAStarResult RoutePlanner::setupHierarchicalSearch(Unit *unit, const Vec2i &dest, TransitionGoal &goalFunc) {
|
||||
PF_TRACE();
|
||||
HAAStarResult RoutePlanner::setupHierarchicalOpenList(Unit *unit, const Vec2i &target) {
|
||||
// get Transitions for start cluster
|
||||
Transitions transitions;
|
||||
Vec2i startCluster = ClusterMap::cellToCluster(unit->getPos());
|
||||
ClusterMap *clusterMap = world->getCartographer()->getClusterMap();
|
||||
clusterMap->getTransitions(startCluster, unit->getCurrField(), transitions);
|
||||
|
||||
DiagonalDistance dd(dest);
|
||||
DiagonalDistance dd(target);
|
||||
nsgSearchEngine->getNeighbourFunc().setSearchCluster(startCluster);
|
||||
|
||||
bool startTrap = true;
|
||||
@ -231,9 +231,9 @@ HAAStarResult RoutePlanner::setupHierarchicalSearch(Unit *unit, const Vec2i &des
|
||||
startTrap = false;
|
||||
}
|
||||
}
|
||||
aMap->clearLocalAnnotations(unit);
|
||||
if (startTrap) {
|
||||
// do again, without annnotations, return TRAPPED if all else goes well
|
||||
aMap->clearLocalAnnotations(unit);
|
||||
bool locked = true;
|
||||
for (Transitions::iterator it = transitions.begin(); it != transitions.end(); ++it) {
|
||||
float cost = quickSearch(unit->getCurrField(), unit->getType()->getSize(), unit->getPos(), (*it)->nwPos);
|
||||
@ -245,23 +245,28 @@ HAAStarResult RoutePlanner::setupHierarchicalSearch(Unit *unit, const Vec2i &des
|
||||
if (locked) {
|
||||
return hsrFailed;
|
||||
}
|
||||
return hsrStartTrap;
|
||||
}
|
||||
return hsrComplete;
|
||||
}
|
||||
|
||||
HAAStarResult RoutePlanner::setupHierarchicalSearch(Unit *unit, const Vec2i &dest, TransitionGoal &goalFunc) {
|
||||
PF_TRACE();
|
||||
|
||||
// set-up open list
|
||||
HAAStarResult res = setupHierarchicalOpenList(unit, dest);
|
||||
if (res == hsrFailed) {
|
||||
return hsrFailed;
|
||||
}
|
||||
bool startTrap = res == hsrStartTrap;
|
||||
|
||||
// transitions to goal
|
||||
transitions.clear();
|
||||
Transitions transitions;
|
||||
Vec2i cluster = ClusterMap::cellToCluster(dest);
|
||||
clusterMap->getTransitions(cluster, unit->getCurrField(), transitions);
|
||||
|
||||
world->getCartographer()->getClusterMap()->getTransitions(cluster, unit->getCurrField(), transitions);
|
||||
nsgSearchEngine->getNeighbourFunc().setSearchCluster(cluster);
|
||||
|
||||
bool goalTrap = true;
|
||||
bool stillAnnotated = startCluster.dist(cluster) < 1.5;
|
||||
if (!stillAnnotated) {
|
||||
aMap->clearLocalAnnotations(unit);
|
||||
}
|
||||
if (stillAnnotated && startTrap) {
|
||||
stillAnnotated = false;
|
||||
}
|
||||
// attempt quick path from dest to each transition,
|
||||
// if successful add transition to goal set
|
||||
for (Transitions::iterator it = transitions.begin(); it != transitions.end(); ++it) {
|
||||
@ -271,22 +276,6 @@ HAAStarResult RoutePlanner::setupHierarchicalSearch(Unit *unit, const Vec2i &des
|
||||
goalTrap = false;
|
||||
}
|
||||
}
|
||||
if (stillAnnotated) {
|
||||
aMap->clearLocalAnnotations(unit);
|
||||
}
|
||||
if (goalTrap) {
|
||||
if (stillAnnotated) {
|
||||
for (Transitions::iterator it = transitions.begin(); it != transitions.end(); ++it) {
|
||||
float cost = quickSearch(unit->getCurrField(), unit->getType()->getSize(), dest, (*it)->nwPos);
|
||||
if (cost != -1.f) {
|
||||
goalFunc.goalTransitions().insert(*it);
|
||||
}
|
||||
}
|
||||
if (goalFunc.goalTransitions().empty()) {
|
||||
return hsrFailed;
|
||||
}
|
||||
}
|
||||
}
|
||||
return startTrap ? hsrStartTrap
|
||||
: goalTrap ? hsrGoalTrap
|
||||
: hsrComplete;
|
||||
@ -317,6 +306,95 @@ HAAStarResult RoutePlanner::findWaypointPath(Unit *unit, const Vec2i &dest, Wayp
|
||||
return hsrFailed;
|
||||
}
|
||||
|
||||
/** goal function for search on cluster map when goal position is unexplored */
|
||||
class UnexploredGoal {
|
||||
private:
|
||||
set<const Transition*> potentialGoals;
|
||||
int team;
|
||||
Map *map;
|
||||
|
||||
public:
|
||||
UnexploredGoal(Map *map, int teamIndex) : team(teamIndex), map(map) {}
|
||||
bool operator()(const Transition *t, const float d) const {
|
||||
Edges::const_iterator it = t->edges.begin();
|
||||
for ( ; it != t->edges.end(); ++it) {
|
||||
if (!map->getSurfaceCell(Map::toSurfCoords((*it)->transition()->nwPos))->isExplored(team)) {
|
||||
// leads to unexplored area, is a potential goal
|
||||
const_cast<UnexploredGoal*>(this)->potentialGoals.insert(t);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// always 'fails', is used to build a list of possible 'avenues of exploration'
|
||||
return false;
|
||||
}
|
||||
|
||||
/** returns the 'potential goal' transition closest to target, or null if no potential goals */
|
||||
const Transition* getBestSeen(const Vec2i &currPos, const Vec2i &target) {
|
||||
const Transition *best = 0;
|
||||
float distToBest = Shared::Graphics::infinity;//1e6f//numeric_limits<float>::infinity();
|
||||
set<const Transition*>::iterator itEnd = potentialGoals.end();
|
||||
for (set<const Transition*>::iterator it = potentialGoals.begin(); it != itEnd; ++it) {
|
||||
float myDist = (*it)->nwPos.dist(target) + (*it)->nwPos.dist(currPos);
|
||||
if (myDist < distToBest) {
|
||||
best = *it;
|
||||
distToBest = myDist;
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
};
|
||||
|
||||
/** cost function for searching cluster map with a unexplored target */
|
||||
class UnexploredCost {
|
||||
Field field;
|
||||
int size;
|
||||
int team;
|
||||
Map *map;
|
||||
|
||||
public:
|
||||
UnexploredCost(Field f, int s, int team, Map *map) : field(f), size(s), team(team), map(map) {}
|
||||
float operator()(const Transition *t, const Transition *t2) const {
|
||||
Edges::const_iterator it = t->edges.begin();
|
||||
for ( ; it != t->edges.end(); ++it) {
|
||||
if ((*it)->transition() == t2) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(it != t->edges.end());
|
||||
if ((*it)->maxClear() >= size
|
||||
&& map->getSurfaceCell(Map::toSurfCoords((*it)->transition()->nwPos))->isExplored(team)) {
|
||||
return (*it)->cost(size);
|
||||
}
|
||||
return -1.f;
|
||||
}
|
||||
};
|
||||
|
||||
HAAStarResult RoutePlanner::findWaypointPathUnExplored(Unit *unit, const Vec2i &dest, WaypointPath &waypoints) {
|
||||
// set-up open list
|
||||
HAAStarResult res = setupHierarchicalOpenList(unit, dest);
|
||||
nsgSearchEngine->getNeighbourFunc().setSearchSpace(ssCellMap);
|
||||
if (res == hsrFailed) {
|
||||
return hsrFailed;
|
||||
}
|
||||
bool startTrap = res == hsrStartTrap;
|
||||
UnexploredGoal goal(world->getMap(), unit->getTeam());
|
||||
UnexploredCost cost(unit->getCurrField(), unit->getType()->getSize(), unit->getTeam(), world->getMap());
|
||||
TransitionHeuristic heuristic(dest);
|
||||
tSearchEngine->aStar(goal, cost, heuristic);
|
||||
const Transition *t = goal.getBestSeen(unit->getPos(), dest);
|
||||
if (!t) {
|
||||
return hsrFailed;
|
||||
}
|
||||
WaypointPath &wpPath = *unit->getWaypointPath();
|
||||
wpPath.clear();
|
||||
while (t) {
|
||||
waypoints.push(t->nwPos);
|
||||
t = tSearchEngine->getPreviousPos(t);
|
||||
}
|
||||
return res; // return setup res (in case of start trap)
|
||||
}
|
||||
|
||||
|
||||
/** refine waypoint path, extend low level path to next waypoint.
|
||||
* @return true if successful, in which case waypoint will have been popped.
|
||||
* false on failure, in which case waypoint will not be popped. */
|
||||
@ -569,7 +647,13 @@ TravelState RoutePlanner::findPathToLocation(Unit *unit, const Vec2i &finalPos)
|
||||
|
||||
// Hierarchical Search
|
||||
tSearchEngine->reset();
|
||||
HAAStarResult res = findWaypointPath(unit, target, wpPath);
|
||||
Map *map = world->getMap();
|
||||
HAAStarResult res;
|
||||
if (map->getSurfaceCell(Map::toSurfCoords(target))->isExplored(unit->getTeam())) {
|
||||
res = findWaypointPath(unit, target, wpPath);
|
||||
} else {
|
||||
res = findWaypointPathUnExplored(unit, target, wpPath);
|
||||
}
|
||||
if (res == hsrFailed) {
|
||||
if (unit->getFaction()->getThisFaction()) {
|
||||
world->getGame()->getConsole()->addLine(Lang::getInstance().get("ImpossibleRoute"));
|
||||
@ -586,12 +670,14 @@ TravelState RoutePlanner::findPathToLocation(Unit *unit, const Vec2i &finalPos)
|
||||
|
||||
PF_TRACE();
|
||||
|
||||
// IF_DEBUG_EDITION( collectWaypointPath(unit); )
|
||||
// IF_DEBUG_EDITION( collectWaypointPath(unit); )
|
||||
//CONSOLE_LOG( "WaypointPath size : " + intToStr(wpPath.size()) )
|
||||
//TODO post process, scan wpPath, if prev.dist(pos) < 4 cull prev
|
||||
assert(wpPath.size() > 1);
|
||||
wpPath.pop();
|
||||
// IF_DEBUG_EDITION( clearOpenClosed(unit->getPos(), target); )
|
||||
if (wpPath.size() > 1) {
|
||||
wpPath.pop();
|
||||
}
|
||||
assert(!wpPath.empty());
|
||||
|
||||
// IF_DEBUG_EDITION( clearOpenClosed(unit->getPos(), target); )
|
||||
// refine path, to at least 20 steps (or end of path)
|
||||
AnnotatedMap *aMap = world->getCartographer()->getMasterMap();
|
||||
aMap->annotateLocal(unit);
|
||||
|
@ -180,8 +180,10 @@ private:
|
||||
bool refinePath(Unit *unit);
|
||||
void smoothPath(Unit *unit);
|
||||
|
||||
HAAStarResult setupHierarchicalOpenList(Unit *unit, const Vec2i &target);
|
||||
HAAStarResult setupHierarchicalSearch(Unit *unit, const Vec2i &dest, TransitionGoal &goalFunc);
|
||||
HAAStarResult findWaypointPath(Unit *unit, const Vec2i &dest, WaypointPath &waypoints);
|
||||
HAAStarResult findWaypointPathUnExplored(Unit *unit, const Vec2i &dest, WaypointPath &waypoints);
|
||||
|
||||
World *world;
|
||||
SearchEngine<NodePool> *nsgSearchEngine;
|
||||
|
@ -235,7 +235,7 @@ public:
|
||||
* @param heuristic heuristic function object
|
||||
*/
|
||||
template< typename GoalFunc, typename CostFunc, typename Heuristic >
|
||||
AStarResult aStar(GoalFunc goalFunc, CostFunc costFunc, Heuristic heuristic) {
|
||||
AStarResult aStar(GoalFunc &goalFunc, CostFunc &costFunc, Heuristic &heuristic) {
|
||||
expanded = 0;
|
||||
DomainKey minPos(invalidKey);
|
||||
vector<DomainKey> neighbours;
|
||||
|
Loading…
x
Reference in New Issue
Block a user