00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "global.hpp"
00018
00019 #include "log.hpp"
00020 #include "map.hpp"
00021 #include "pathfind/pathfind.hpp"
00022 #include "pathfind/teleport.hpp"
00023 #include "foreach.hpp"
00024
00025 #include <queue>
00026 #include <map>
00027
00028 static lg::log_domain log_engine("engine");
00029 #define LOG_PF LOG_STREAM(info, log_engine)
00030 #define DBG_PF LOG_STREAM(debug, log_engine)
00031 #define ERR_PF LOG_STREAM(err, log_engine)
00032
00033 namespace {
00034 double heuristic(const map_location& src, const map_location& dst)
00035 {
00036
00037
00038
00039
00040
00041 double xdiff = (src.x - dst.x) * 0.75;
00042
00043 double ydiff = (src.y - dst.y) + ((src.x & 1) - (dst.x & 1)) * 0.5;
00044
00045
00046
00047
00048
00049
00050
00051
00052 return distance_between(src, dst) + (xdiff*xdiff + ydiff*ydiff) / 900000000.0;
00053
00054
00055
00056
00057 }
00058
00059
00060 const unsigned bad_search_counter = 0;
00061
00062 static unsigned search_counter = bad_search_counter;
00063
00064 struct node {
00065 double g, h, t;
00066 map_location curr, prev;
00067
00068
00069
00070
00071
00072 unsigned in;
00073
00074 node()
00075 : g(1e25)
00076 , h(1e25)
00077 , t(1e25)
00078 , curr()
00079 , prev()
00080 , in(bad_search_counter)
00081 {
00082 }
00083 node(double s, const map_location &c, const map_location &p, const map_location &dst, bool i, const pathfind::teleport_map* teleports):
00084 g(s), h(heuristic(c, dst)), t(g + h), curr(c), prev(p), in(search_counter + i)
00085 {
00086 if (teleports && !teleports->empty()) {
00087
00088 double new_srch = 1.0;
00089 std::set<map_location> sources;
00090 teleports->get_sources(sources);
00091
00092 std::set<map_location>::const_iterator it = sources.begin();
00093 for(; it != sources.end(); ++it) {
00094 const double tmp_srch = heuristic(c, *it);
00095 if (tmp_srch < new_srch) { new_srch = tmp_srch; }
00096 }
00097
00098
00099 double new_dsth = 1.0;
00100 std::set<map_location> targets;
00101 teleports->get_targets(targets);
00102
00103 for(it = targets.begin(); it != targets.end(); ++it) {
00104 const double tmp_dsth = heuristic(*it, dst);
00105 if (tmp_dsth < new_dsth) { new_dsth = tmp_dsth; }
00106 }
00107
00108 double new_h = new_srch + new_dsth + 1.0;
00109 if (new_h < h) {
00110 h = new_h;
00111 t = g + h;
00112 }
00113 }
00114 }
00115
00116 bool operator<(const node& o) const {
00117 return t < o.t;
00118 }
00119 };
00120
00121 class comp {
00122 const std::vector<node>& nodes_;
00123
00124 public:
00125 comp(const std::vector<node>& n) : nodes_(n) { }
00126 bool operator()(int a, int b) {
00127 return nodes_[b] < nodes_[a];
00128 }
00129 };
00130
00131 class indexer {
00132 size_t h_, w_;
00133
00134 public:
00135 indexer(size_t a, size_t b) : h_(a), w_(b) { }
00136 size_t operator()(const map_location& loc) {
00137 return loc.y * h_ + loc.x;
00138 }
00139 };
00140 }
00141
00142
00143 pathfind::plain_route pathfind::a_star_search(const map_location& src, const map_location& dst,
00144 double stop_at, const cost_calculator *calc, const size_t width,
00145 const size_t height,
00146 const teleport_map *teleports) {
00147
00148 assert(src.valid(width, height));
00149 assert(dst.valid(width, height));
00150 assert(calc != NULL);
00151 assert(stop_at <= calc->getNoPathValue());
00152
00153
00154 DBG_PF << "A* search: " << src << " -> " << dst << '\n';
00155
00156 if (calc->cost(dst, 0) >= stop_at) {
00157 LOG_PF << "aborted A* search because Start or Dest is invalid\n";
00158 pathfind::plain_route locRoute;
00159 locRoute.move_cost = int(calc->getNoPathValue());
00160 return locRoute;
00161 }
00162
00163
00164 search_counter += 2;
00165 if (search_counter - bad_search_counter <= 1u)
00166 search_counter += 2;
00167
00168 static std::vector<node> nodes;
00169 nodes.resize(width * height);
00170
00171 indexer index(width, height);
00172 comp node_comp(nodes);
00173
00174 nodes[index(dst)].g = stop_at + 1;
00175 nodes[index(src)] = node(0, src, map_location::null_location, dst, true, teleports);
00176
00177 std::vector<int> pq;
00178 pq.push_back(index(src));
00179
00180 while (!pq.empty()) {
00181 node& n = nodes[pq.front()];
00182
00183 n.in = search_counter;
00184
00185 std::pop_heap(pq.begin(), pq.end(), node_comp);
00186 pq.pop_back();
00187
00188 if (n.t >= nodes[index(dst)].g) break;
00189
00190 std::vector<map_location> locs;
00191
00192 int i;
00193 if (teleports && !teleports->empty()) {
00194
00195 std::set<map_location> allowed_teleports;
00196 teleports->get_adjacents(allowed_teleports, n.curr);
00197
00198 i = allowed_teleports.size() +6;
00199 locs = std::vector<map_location>(i);
00200
00201 std::copy(allowed_teleports.begin(), allowed_teleports.end(), locs.begin() + 6);
00202 } else
00203 { locs = std::vector<map_location>(6); i = 6;}
00204
00205 get_adjacent_tiles(n.curr, &locs[0]);
00206
00207 for (; i-- > 0;) {
00208 if (!locs[i].valid(width, height)) continue;
00209 if (locs[i] == n.curr) continue;
00210 node& next = nodes[index(locs[i])];
00211
00212 double thresh = (next.in - search_counter <= 1u) ? next.g : stop_at + 1;
00213
00214 if (n.g + 1 >= thresh) continue;
00215 double cost = n.g + calc->cost(locs[i], n.g);
00216 if (cost >= thresh) continue;
00217
00218 bool in_list = next.in == search_counter + 1;
00219
00220 next = node(cost, locs[i], n.curr, dst, true, teleports);
00221
00222 if (in_list) {
00223 std::push_heap(pq.begin(), std::find(pq.begin(), pq.end(), static_cast<int>(index(locs[i]))) + 1, node_comp);
00224 } else {
00225 pq.push_back(index(locs[i]));
00226 std::push_heap(pq.begin(), pq.end(), node_comp);
00227 }
00228 }
00229 }
00230
00231 pathfind::plain_route route;
00232 if (nodes[index(dst)].g <= stop_at) {
00233 DBG_PF << "found solution; calculating it...\n";
00234 route.move_cost = static_cast<int>(nodes[index(dst)].g);
00235 for (node curr = nodes[index(dst)]; curr.prev != map_location::null_location; curr = nodes[index(curr.prev)]) {
00236 route.steps.push_back(curr.curr);
00237 }
00238 route.steps.push_back(src);
00239 std::reverse(route.steps.begin(), route.steps.end());
00240 } else {
00241 LOG_PF << "aborted a* search " << "\n";
00242 route.move_cost = static_cast<int>(calc->getNoPathValue());
00243 }
00244
00245 return route;
00246 }
00247