/** * Calculate the shortest path using a simple A-Star algorithm. * The unit information and movement type must have already been set. * The path information is set only if a valid path is found. * @param startPosition The position to start from. * @param endPosition The position we want to reach. * @return True if a path exists, false otherwise. */ bool Pathfinding::aStarPath(const Position &startPosition, const Position &endPosition) { // reset every node, so we have to check them all for (std::vector<PathfindingNode>::iterator it = _nodes.begin(); it != _nodes.end(); ++it) it->reset(); // start position is the first one in our "open" list PathfindingNode *start = getNode(startPosition); start->connect(0, 0, 0, endPosition); PathfindingOpenSet openList; openList.push(start); // if the open list is empty, we've reached the end while(!openList.empty()) { PathfindingNode *currentNode = openList.pop(); Position const ¤tPos = currentNode->getPosition(); currentNode->setChecked(); if (currentPos == endPosition) // We found our target. { _path.clear(); PathfindingNode *pf = currentNode; while (pf->getPrevNode()) { _path.push_back(pf->getPrevDir()); pf = pf->getPrevNode(); } return true; } // Try all reachable neighbours. for (int direction = 0; direction < 10; direction++) { Position nextPos; int tuCost = getTUCost(currentPos, direction, &nextPos, _unit); if (tuCost == 255) // Skip unreachable / blocked continue; PathfindingNode *nextNode = getNode(nextPos); if (nextNode->isChecked()) // Our algorithm means this node is already at minimum cost. continue; int totalTuCost = currentNode->getTUCost() + tuCost; // If this node is unvisited or visited from a better path. if (!nextNode->inOpenSet() || nextNode->getTUCost() > totalTuCost) { nextNode->connect(totalTuCost, currentNode, direction, endPosition); openList.push(nextNode); } } } // Unble to reach the target return false; }
/** * Use Dijkstra's algorithm to locate all tiles reachable to @a *unit with a TU cost no more than @a tuMax. * @param unit Pointer to the unit. * @param tuMax The maximum cost of the path to each tile. * @return An array of reachable tiles, sorted in ascending order of cost. The first tile is the start location. */ std::vector<int> Pathfinding::findReachable(BattleUnit *unit, int tuMax) { const Position &start = unit->getPosition(); for (std::vector<PathfindingNode>::iterator it = _nodes.begin(); it != _nodes.end(); ++it) { it->reset(); } PathfindingNode *startNode = getNode(start); startNode->connect(0, 0, 0); PathfindingOpenSet unvisited; unvisited.push(startNode); std::vector<PathfindingNode*> reachable; while (!unvisited.empty()) { PathfindingNode *currentNode = unvisited.pop(); Position const ¤tPos = currentNode->getPosition(); // Try all reachable neighbours. for (int direction = 0; direction < 10; direction++) { Position nextPos; int tuCost = getTUCost(currentPos, direction, &nextPos, unit); if (tuCost == 255) // Skip unreachable / blocked continue; if (tuCost > tuMax) // Run out of TUs continue; PathfindingNode *nextNode = getNode(nextPos); if (nextNode->isChecked()) // Our algorithm means this node is already at minimum cost. continue; int totalTuCost = currentNode->getTUCost() + tuCost; // If this node is unvisited or visited from a better path. if (!nextNode->inOpenSet() || nextNode->getTUCost() > totalTuCost) { nextNode->connect(totalTuCost, currentNode, direction); unvisited.push(nextNode); } } currentNode->setChecked(); reachable.push_back(currentNode); } std::sort(reachable.begin(), reachable.end(), MinNodeCosts()); std::vector<int> tiles; tiles.reserve(reachable.size()); for (std::vector<PathfindingNode*>::const_iterator it = reachable.begin(); it != reachable.end(); ++it) { tiles.push_back(_save->getTileIndex((*it)->getPosition())); } return tiles; }