void AIConstruction::SetFlagsAlongRoad(const noRoadNode& roadNode, Direction dir) { // does the roadsegment still exist? const RoadSegment& roadSeg = *roadNode.GetRoute(dir); bool isBwdDir = roadSeg.GetNodeID(roadNode); MapPoint curPos = roadNode.GetPos(); // Skip first curPos = aii.gwb.GetNeighbour(curPos, roadSeg.GetDir(isBwdDir, 0)); // Start after getting first neighbor (min distance == 2) // and skip last 2 points (min distance and last is flag) for(unsigned i = 1; i + 2 < roadSeg.GetLength(); ++i) { curPos = aii.gwb.GetNeighbour(curPos, roadSeg.GetDir(isBwdDir, i)); aii.SetFlag(curPos); constructionlocations.push_back(curPos); } }
unsigned operator()(const noRoadNode& curNode, const unsigned char nextDir) const { // Im Warenmodus m�ssen wir Strafpunkte für �berlastete Tr�ger hinzuaddieren, // damit der Algorithmus auch Ausweichrouten ausw�hlt return curNode.GetPunishmentPoints(nextDir); }
bool RoadPathFinder::FindPathImpl(const noRoadNode& start, const noRoadNode& goal, const unsigned max, const T_AdditionalCosts addCosts, const T_SegmentConstraints isSegmentAllowed, unsigned* const length, unsigned char* const firstDir, MapPoint* const firstNodePos) { if(&start == &goal) { // Path where start==goal should never happen RTTR_Assert(false); LOG.write("WARNING: Bug detected (GF: %u). Please report this with the savegame and replay (Start==Goal in pathfinding %u,%u)\n") % gwb_.GetEvMgr().GetCurrentGF() % unsigned(start.GetX()) % unsigned(start.GetY()); // But for now we assume it to be valid and return (kind of) correct values if(length) *length = 0; if(firstDir) *firstDir = 0xff; if(firstNodePos) *firstNodePos = start.GetPos(); return true; } // increase current_visit_on_roads, so we don't have to clear the visited-states at every run currentVisit++; // if the counter reaches its maxium, tidy up if (currentVisit == std::numeric_limits<unsigned>::max()) { int w = gwb_.GetWidth(); int h = gwb_.GetHeight(); for(int y = 0; y < h; y++) { for(int x = 0; x < w; x++) { noRoadNode* const node = gwb_.GetSpecObj<noRoadNode>(MapPoint(x, y)); if(node) node->last_visit = 0; } } currentVisit = 1; } // Anfangsknoten einf�gen todo.clear(); start.targetDistance = gwb_.CalcDistance(start.GetPos(), goal.GetPos()); start.estimate = start.targetDistance; start.last_visit = currentVisit; start.prev = NULL; start.cost = 0; start.dir_ = 0; todo.push(&start); while (!todo.empty()) { // Knoten mit den geringsten Wegkosten ausw�hlen const noRoadNode& best = *todo.pop(); // Ziel erreicht? if (&best == &goal) { // Jeweils die einzelnen Angaben zur�ckgeben, falls gew�nscht (Pointer �bergeben) if (length) *length = best.cost; // Backtrace to get the last node that is not the start node (has a prev node) --> Next node from start on path const noRoadNode* firstNode = &best; while(firstNode->prev != &start) { firstNode = firstNode->prev; } if (firstDir) *firstDir = (unsigned char) firstNode->dir_; if (firstNodePos) *firstNodePos = firstNode->GetPos(); // Done, path found return true; } // Nachbarflagge bzw. Wege in allen 6 Richtungen verfolgen for (unsigned i = 0; i < 6; ++i) { // Gibt es auch einen solchen Weg bzw. Nachbarflagge? noRoadNode* neighbour = best.GetNeighbour(i); // Wenn nicht, brauchen wir mit dieser Richtung gar nicht weiter zu machen if (!neighbour) continue; // this eliminates 1/6 of all nodes and avoids cost calculation and further checks, // therefore - and because the profiler says so - it is more efficient that way if (neighbour == best.prev) continue; // No pathes over buildings if ((i == 1) && (neighbour != &goal)) { // Flags and harbors are allowed const GO_Type got = neighbour->GetGOT(); if(got != GOT_FLAG && got != GOT_NOB_HARBORBUILDING) continue; } // evtl verboten? if(!isSegmentAllowed(*best.routes[i])) continue; // Neuer Weg für diesen neuen Knoten berechnen unsigned cost = best.cost + best.routes[i]->GetLength(); cost += addCosts(best, i); if (cost > max) continue; // Was node already visited? if (neighbour->last_visit == currentVisit) { // Dann nur ggf. Weg und Vorg�nger korrigieren, falls der Weg k�rzer ist if (cost < neighbour->cost) { neighbour->cost = cost; neighbour->prev = &best; neighbour->estimate = neighbour->targetDistance + cost; todo.rearrange(neighbour); neighbour->dir_ = i; } }else { // Not visited yet -> Add to list neighbour->last_visit = currentVisit; neighbour->cost = cost; neighbour->dir_ = i; neighbour->prev = &best; neighbour->targetDistance = gwb_.CalcDistance(neighbour->GetPos(), goal.GetPos()); neighbour->estimate = neighbour->targetDistance + cost; todo.push(neighbour); } } // Stehen wir hier auf einem Hafenplatz if (best.GetGOT() == GOT_NOB_HARBORBUILDING) { std::vector<nobHarborBuilding::ShipConnection> scs = static_cast<const nobHarborBuilding&>(best).GetShipConnections(); for (unsigned i = 0; i < scs.size(); ++i) { // Neuer Weg für diesen neuen Knoten berechnen unsigned cost = best.cost + scs[i].way_costs; if (cost > max) continue; noRoadNode& dest = *scs[i].dest; // Was node already visited? if (dest.last_visit == currentVisit) { // Dann nur ggf. Weg und Vorg�nger korrigieren, falls der Weg k�rzer ist if (cost < dest.cost) { dest.dir_ = SHIP_DIR; dest.cost = cost; dest.prev = &best; dest.estimate = dest.targetDistance + cost; todo.rearrange(&dest); } }else { // Not visited yet -> Add to list dest.last_visit = currentVisit; dest.dir_ = SHIP_DIR; dest.prev = &best; dest.cost = cost; dest.targetDistance = gwb_.CalcDistance(dest.GetPos(), goal.GetPos()); dest.estimate = dest.targetDistance + cost; todo.push(&dest); } } } } // Liste leer und kein Ziel erreicht --> kein Weg return false; }