Teleport path finding improvement (resolves #9434)
* Removed duplicate map_location hasher, removed unused teleport_id variable, dst_node reference is used at other possible locations, teleport destination heuristic distance now calculated before path finding loop only once, teleport source heuristic distance now stored in nodes, only calculated once and reused. --------- Co-authored-by: SomeName42 <>
This commit is contained in:
parent
36146c5c6c
commit
f13d4fe2a4
4 changed files with 63 additions and 68 deletions
|
@ -257,7 +257,7 @@ Any units adjacent to this unit will fight as if it were dusk when it is night,
|
|||
[tunnel]
|
||||
id=village_teleport
|
||||
[source]
|
||||
terrain=*^V*
|
||||
gives_income=true
|
||||
formula="
|
||||
owner_side = teleport_unit.side_number and (unit = teleport_unit or not unit)
|
||||
where
|
||||
|
@ -266,7 +266,7 @@ Any units adjacent to this unit will fight as if it were dusk when it is night,
|
|||
[/source]
|
||||
|
||||
[target]
|
||||
terrain=*^V*
|
||||
gives_income=true
|
||||
formula="owner_side = teleport_unit.side_number and not unit_at(loc)"
|
||||
[/target]
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ const unsigned bad_search_counter = 0;
|
|||
static unsigned search_counter = bad_search_counter;
|
||||
|
||||
struct node {
|
||||
double g, h, t;
|
||||
double g, h, t, srch;
|
||||
map_location curr, prev;
|
||||
/**
|
||||
* If equal to search_counter, the node is off the list.
|
||||
|
@ -78,29 +78,20 @@ struct node {
|
|||
, in(bad_search_counter)
|
||||
{
|
||||
}
|
||||
node(double s, const map_location &c, const map_location &p, const map_location &dst, bool i, const teleport_map* teleports):
|
||||
g(s), h(heuristic(c, dst)), t(g + h), curr(c), prev(p), in(search_counter + i)
|
||||
node(double s, const map_location &c, const map_location &p, const map_location &dst, bool i, const teleport_map* teleports, double srch_arg, double dsth):
|
||||
g(s), h(heuristic(c, dst)), t(g + h), srch(srch_arg), curr(c), prev(p), in(search_counter + i)
|
||||
{
|
||||
if (teleports && !teleports->empty()) {
|
||||
if(srch < 0) {
|
||||
srch = 1.0;
|
||||
|
||||
double new_srch = 1.0;
|
||||
auto sources = teleports->get_sources();
|
||||
|
||||
std::set<map_location>::const_iterator it = sources.begin();
|
||||
for(; it != sources.end(); ++it) {
|
||||
const double tmp_srch = heuristic(c, *it);
|
||||
if (tmp_srch < new_srch) { new_srch = tmp_srch; }
|
||||
for(const auto& it : teleports->get_sources()) {
|
||||
const double tmp_srch = heuristic(c, it);
|
||||
if (tmp_srch < srch) { srch = tmp_srch; }
|
||||
}
|
||||
}
|
||||
|
||||
double new_dsth = 1.0;
|
||||
auto targets = teleports->get_targets();
|
||||
|
||||
for(it = targets.begin(); it != targets.end(); ++it) {
|
||||
const double tmp_dsth = heuristic(*it, dst);
|
||||
if (tmp_dsth < new_dsth) { new_dsth = tmp_dsth; }
|
||||
}
|
||||
|
||||
double new_h = new_srch + new_dsth + 1.0;
|
||||
double new_h = srch + dsth + 1.0;
|
||||
if (new_h < h) {
|
||||
h = new_h;
|
||||
t = g + h;
|
||||
|
@ -159,14 +150,24 @@ plain_route a_star_search(const map_location& src, const map_location& dst,
|
|||
if (search_counter - bad_search_counter <= 1u)
|
||||
search_counter += 2;
|
||||
|
||||
double dsth = 1.0;
|
||||
if (teleports && !teleports->empty()) {
|
||||
for(const auto &it : teleports->get_targets()) {
|
||||
const double tmp_dsth = heuristic(it, dst);
|
||||
if (tmp_dsth < dsth) { dsth = tmp_dsth; }
|
||||
}
|
||||
}
|
||||
|
||||
static std::vector<node> nodes;
|
||||
nodes.resize(width * height); // this create uninitialized nodes
|
||||
|
||||
indexer index(width);
|
||||
comp node_comp(nodes);
|
||||
|
||||
nodes[index(dst)].g = stop_at + 1;
|
||||
nodes[index(src)] = node(0, src, map_location::null_location(), dst, true, teleports);
|
||||
node& dst_node = nodes[index(dst)];
|
||||
|
||||
dst_node.g = stop_at + 1;
|
||||
nodes[index(src)] = node(0, src, map_location::null_location(), dst, true, teleports, -1, dsth);
|
||||
|
||||
std::vector<int> pq;
|
||||
pq.push_back(index(src));
|
||||
|
@ -179,13 +180,13 @@ plain_route a_star_search(const map_location& src, const map_location& dst,
|
|||
std::pop_heap(pq.begin(), pq.end(), node_comp);
|
||||
pq.pop_back();
|
||||
|
||||
if (n.t >= nodes[index(dst)].g) break;
|
||||
if (n.t >= dst_node.g) break;
|
||||
|
||||
std::vector<map_location> locs(6);
|
||||
get_adjacent_tiles(n.curr, locs.data());
|
||||
|
||||
if (teleports && !teleports->empty()) {
|
||||
auto allowed_teleports = teleports->get_adjacents(n.curr);
|
||||
const auto& allowed_teleports = teleports->get_adjacents(n.curr);
|
||||
locs.insert(locs.end(), allowed_teleports.begin(), allowed_teleports.end());
|
||||
}
|
||||
|
||||
|
@ -195,8 +196,15 @@ plain_route a_star_search(const map_location& src, const map_location& dst,
|
|||
if (!loc.valid(width, height, border)) continue;
|
||||
if (loc == n.curr) continue;
|
||||
node& next = nodes[index(loc)];
|
||||
|
||||
double thresh = (next.in - search_counter <= 1u) ? next.g : stop_at + 1;
|
||||
double srch;
|
||||
double thresh;
|
||||
if(next.in - search_counter <= 1u) {
|
||||
srch = next.srch;
|
||||
thresh = next.g;
|
||||
} else {
|
||||
srch = -1;
|
||||
thresh = dst_node.g;
|
||||
}
|
||||
// cost() is always >= 1 (assumed and needed by the heuristic)
|
||||
if (n.g + 1 >= thresh) continue;
|
||||
double cost = n.g + calc.cost(loc, n.g);
|
||||
|
@ -204,7 +212,7 @@ plain_route a_star_search(const map_location& src, const map_location& dst,
|
|||
|
||||
bool in_list = next.in == search_counter + 1;
|
||||
|
||||
next = node(cost, loc, n.curr, dst, true, teleports);
|
||||
next = node(cost, loc, n.curr, dst, true, teleports, srch, dsth);
|
||||
|
||||
if (in_list) {
|
||||
std::push_heap(pq.begin(), std::find(pq.begin(), pq.end(), static_cast<int>(index(loc))) + 1, node_comp);
|
||||
|
@ -216,10 +224,10 @@ plain_route a_star_search(const map_location& src, const map_location& dst,
|
|||
}
|
||||
|
||||
plain_route route;
|
||||
if (nodes[index(dst)].g <= stop_at) {
|
||||
if (dst_node.g <= stop_at) {
|
||||
DBG_PF << "found solution; calculating it...";
|
||||
route.move_cost = static_cast<int>(nodes[index(dst)].g);
|
||||
for (node curr = nodes[index(dst)]; curr.prev != map_location::null_location(); curr = nodes[index(curr.prev)]) {
|
||||
route.move_cost = static_cast<int>(dst_node.g);
|
||||
for (node curr = dst_node; curr.prev != map_location::null_location(); curr = nodes[index(curr.prev)]) {
|
||||
route.steps.push_back(curr.curr);
|
||||
}
|
||||
route.steps.push_back(src);
|
||||
|
|
|
@ -215,56 +215,39 @@ teleport_map::teleport_map(
|
|||
}
|
||||
}
|
||||
|
||||
std::string teleport_id = group.get_teleport_id();
|
||||
std::set<map_location>::iterator source_it = locations.first.begin();
|
||||
for (; source_it != locations.first.end(); ++source_it ) {
|
||||
if(teleport_map_.count(*source_it) == 0) {
|
||||
std::set<std::string> id_set;
|
||||
id_set.insert(teleport_id);
|
||||
teleport_map_.emplace(*source_it, id_set);
|
||||
auto map_it = teleport_map_.find(*source_it);
|
||||
|
||||
if(map_it == teleport_map_.end()) {
|
||||
teleport_map_.emplace(*source_it, std::unordered_set(locations.second.begin(), locations.second.end()));
|
||||
} else {
|
||||
(teleport_map_.find(*source_it)->second).insert(teleport_id);
|
||||
map_it->second.insert(locations.second.begin(), locations.second.end());
|
||||
}
|
||||
}
|
||||
sources_.emplace(teleport_id, locations.first);
|
||||
targets_.emplace(teleport_id, locations.second);
|
||||
sources_.insert(locations.first.begin(), locations.first.end());
|
||||
targets_.insert(locations.second.begin(), locations.second.end());
|
||||
}
|
||||
}
|
||||
|
||||
std::set<map_location> teleport_map::get_adjacents(map_location loc) const
|
||||
const std::unordered_set<map_location>& teleport_map::get_adjacents(map_location loc) const
|
||||
{
|
||||
const auto iter = teleport_map_.find(loc);
|
||||
if(iter == teleport_map_.end()) {
|
||||
return {};
|
||||
return empty_set_;
|
||||
}
|
||||
|
||||
std::set<map_location> res;
|
||||
for(const std::string& key : iter->second) {
|
||||
const auto& target = targets_.find(key)->second;
|
||||
res.insert(target.begin(), target.end());
|
||||
}
|
||||
|
||||
return res;
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
std::set<map_location> teleport_map::get_sources() const
|
||||
const std::unordered_set<map_location>& teleport_map::get_sources() const
|
||||
{
|
||||
std::set<map_location> res;
|
||||
for(const auto& src : sources_) {
|
||||
res.insert(src.second.begin(), src.second.end());
|
||||
}
|
||||
|
||||
return res;
|
||||
return sources_;
|
||||
}
|
||||
|
||||
std::set<map_location> teleport_map::get_targets() const
|
||||
const std::unordered_set<map_location>& teleport_map::get_targets() const
|
||||
{
|
||||
std::set<map_location> res;
|
||||
for(const auto& tgt : targets_) {
|
||||
res.insert(tgt.second.begin(), tgt.second.end());
|
||||
}
|
||||
|
||||
return res;
|
||||
return targets_;
|
||||
}
|
||||
|
||||
const teleport_map get_teleport_locations(const unit &u,
|
||||
|
|
|
@ -18,6 +18,9 @@
|
|||
#include "config.hpp"
|
||||
#include "map/location.hpp"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
class team;
|
||||
class unit;
|
||||
class vconfig;
|
||||
|
@ -120,13 +123,13 @@ public:
|
|||
* @param loc the map location for which we want to know the adjacent hexes
|
||||
* @todo what does this function actually have to do with adjacent hexes?
|
||||
*/
|
||||
std::set<map_location> get_adjacents(map_location loc) const;
|
||||
const std::unordered_set<map_location>& get_adjacents(map_location loc) const;
|
||||
|
||||
/** Returns the locations that are an entrance of the tunnel. */
|
||||
std::set<map_location> get_sources() const;
|
||||
const std::unordered_set<map_location>& get_sources() const;
|
||||
|
||||
/** Returns the locations that are an exit of the tunnel. */
|
||||
std::set<map_location> get_targets() const;
|
||||
const std::unordered_set<map_location>& get_targets() const;
|
||||
|
||||
/*
|
||||
* @returns whether the teleport_map does contain any defined tunnel
|
||||
|
@ -136,9 +139,10 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
std::map<map_location, std::set<std::string>> teleport_map_;
|
||||
std::map<std::string, std::set<map_location>> sources_;
|
||||
std::map<std::string, std::set<map_location>> targets_;
|
||||
std::unordered_map<map_location, std::unordered_set<map_location>> teleport_map_;
|
||||
std::unordered_set<map_location> sources_;
|
||||
std::unordered_set<map_location> targets_;
|
||||
std::unordered_set<map_location> empty_set_;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
Loading…
Add table
Reference in a new issue