00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #ifndef PATHFIND_ASTAR_H
00011 #define PATHFIND_ASTAR_H
00012
00013 #include <list>
00014 #include <memory>
00015 #include <queue>
00016 #include <set>
00017 #include "marker.h"
00018 #include "search.h"
00019
00020
00021
00022 namespace PathFind
00023 {
00024
00025 using namespace std;
00026
00027
00028 class AStarNode
00029 {
00030 public:
00031
00032 class Compare
00033 {
00034 public:
00035 virtual ~Compare();
00036
00037 bool operator()(const AStarNode& node1,
00038 const AStarNode& node2);
00039 };
00040
00041 int m_nodeId;
00042
00043 int m_parent;
00044
00045 int m_g;
00046
00047 int m_h;
00048
00049 int m_f;
00050
00051 AStarNode()
00052 {
00053 }
00054
00055 AStarNode(int nodeId, int parent, int g, int h)
00056 : m_nodeId(nodeId),
00057 m_parent(parent),
00058 m_g(g),
00059 m_h(h),
00060 m_f(g + h)
00061 {
00062 }
00063
00064 void print(ostream& ostrm) const;
00065 };
00066
00067
00068 class AStarClosed
00069 {
00070 public:
00071 void add(const AStarNode& node);
00072
00073 vector<int> constructPath(int start, int target);
00074
00075 void init(int maxNodeId);
00076
00077 void print(ostream& ostrm) const;
00078
00079 void remove(int nodeId);
00080
00081 const AStarNode* search(int nodeId) const;
00082
00083 private:
00084 list<AStarNode> m_list;
00085 };
00086
00087
00088 template<class MARKER>
00089 class AStarClosedLookup
00090 {
00091 public:
00092 AStarClosedLookup();
00093
00094 void add(const AStarNode& node);
00095
00096 vector<int> constructPath(int start, int target);
00097
00098 void init(int maxNodeId);
00099
00100 void print(ostream& ostrm) const;
00101
00102 void remove(int nodeId);
00103
00104 const AStarNode* search(int nodeId) const;
00105
00106 private:
00107 int m_maxNodeId;
00108
00109 MARKER m_marker;
00110
00111 vector<AStarNode> m_nodes;
00112 };
00113
00114
00115 template<class MARKER>
00116 class AStarOpen
00117 {
00118 public:
00119 AStarOpen();
00120
00121 void init(int numberNodes);
00122
00123 void insert(const AStarNode& node);
00124
00125 bool isEmpty() const
00126 {
00127 return (m_nodes.size() == 0);
00128 }
00129
00130 AStarNode pop();
00131
00132 void print(ostream& ostrm) const;
00133
00134 bool remove(int nodeId);
00135
00136 const AStarNode* search(int nodeId) const;
00137
00138 private:
00139 typedef multiset<AStarNode, AStarNode::Compare> NodeSet;
00140
00141 typedef NodeSet::const_iterator NodeSetConstIterator;
00142
00143 typedef NodeSet::iterator NodeSetIterator;
00144
00145 int m_numberNodes;
00146
00147 MARKER m_marker;
00148
00149
00150 vector<NodeSetIterator> m_lookupTable;
00151
00152 NodeSet m_nodes;
00153 };
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200 template<class MARKER = MarkerFastClear,
00201 class CLOSED = AStarClosedLookup<MARKER> >
00202 class AStar
00203 : public Search
00204 {
00205 public:
00206 AStar();
00207
00208 StatisticsCollection createStatistics();
00209
00210 bool findPath(const Environment& env, int start, int target);
00211
00212 const vector<int>& getPath() const
00213 {
00214 return m_path;
00215 }
00216
00217 const StatisticsCollection& getStatistics() const;
00218
00219
00220 const vector<char>& getVisitedNodes() const
00221 {
00222 return m_visitedNodes;
00223 }
00224
00225 void setNodesLimit(long long int nodesLimit)
00226 {
00227 m_nodesLimit = nodesLimit;
00228 }
00229
00230 int getPathCost() const
00231 {
00232 return m_pathCost;
00233 }
00234
00235 private:
00236 int m_pathCost;
00237
00238 int m_target;
00239
00240 const Environment* m_env;
00241
00242 long long int m_nodesExpanded;
00243
00244 long long int m_nodesVisited;
00245
00246 CLOSED m_closed;
00247
00248 vector<char> m_visitedNodes;
00249
00250 vector<int> m_path;
00251
00252 AStarOpen<MARKER> m_open;
00253
00254 StatisticsCollection m_statistics;
00255
00256 Statistics& m_branchingFactor;
00257
00258
00259 const AStarNode* findNode(int nodeId);
00260
00261 void findPathAStar(int start);
00262
00263
00264 void finishSearch(int start, const AStarNode& node);
00265
00266 AStarNode getBestNodeFromOpen();
00267 };
00268
00269 }
00270
00271
00272
00273 namespace PathFind
00274 {
00275
00276 using namespace std;
00277
00278 template<class MARKER, class CLOSED>
00279 AStar<MARKER, CLOSED>::AStar()
00280 : m_statistics(createStatistics()),
00281 m_branchingFactor(m_statistics.get("branching_factor"))
00282 {
00283 }
00284
00285 template<class MARKER, class CLOSED>
00286 StatisticsCollection AStar<MARKER, CLOSED>::createStatistics()
00287 {
00288 StatisticsCollection collection;
00289 collection.create("cpu_time");
00290 collection.create("path_cost");
00291 collection.create("path_length");
00292 collection.create("branching_factor");
00293 collection.create("nodes_expanded");
00294 collection.create("nodes_visited");
00295 return collection;
00296 }
00297
00298 template<class MARKER, class CLOSED>
00299 const AStarNode* AStar<MARKER, CLOSED>::findNode(int nodeId)
00300 {
00301 const AStarNode* result = 0;
00302 result = m_open.search(nodeId);
00303 if (result != 0)
00304 return result;
00305 result = m_closed.search(nodeId);
00306 return result;
00307 }
00308
00309 template<class MARKER, class CLOSED>
00310 bool AStar<MARKER, CLOSED>::findPath(const Environment& env, int start,
00311 int target)
00312 {
00313 assert(env.isValidNodeId(start));
00314 assert(env.isValidNodeId(target));
00315 clock_t startTime = clock();
00316 m_statistics.clear();
00317 m_nodesExpanded = 0;
00318 m_nodesVisited = 0;
00319 m_env = &env;
00320 m_target = target;
00321 m_path.clear();
00322 m_visitedNodes.resize(env.getNumberNodes());
00323 fill(m_visitedNodes.begin(), m_visitedNodes.end(), ' ');
00324 findPathAStar(start);
00325 double timeDiff =
00326 static_cast<double>(clock() - startTime) / CLOCKS_PER_SEC;
00327 m_statistics.get("cpu_time").add(timeDiff);
00328 m_statistics.get("nodes_expanded").add(m_nodesExpanded);
00329 m_statistics.get("nodes_visited").add(m_nodesVisited);
00330 m_statistics.get("path_length").add(m_path.size());
00331 return true;
00332 }
00333
00334 template<class MARKER, class CLOSED>
00335 void AStar<MARKER, CLOSED>::findPathAStar(int start)
00336 {
00337 int numberNodes = m_env->getNumberNodes();
00338 m_closed.init(numberNodes);
00339 m_open.init(numberNodes);
00340 int heuristic = m_env->getHeuristic(start, m_target);
00341 m_pathCost = -1;
00342 AStarNode startNode(start, NO_NODE, 0, heuristic);
00343 m_open.insert(startNode);
00344 vector<Environment::Successor> successors;
00345 while (! m_open.isEmpty())
00346 {
00347
00348 AStarNode node = getBestNodeFromOpen();
00349
00350 if (node.m_nodeId == m_target)
00351 {
00352 finishSearch(start, node);
00353 return;
00354 }
00355 ++m_nodesExpanded;
00356 m_env->getSuccessors(node.m_nodeId, NO_NODE, successors);
00357 m_branchingFactor.add(successors.size());
00358 for (vector<Environment::Successor>::const_iterator i
00359 = successors.begin(); i != successors.end(); ++i)
00360 {
00361 int newg = node.m_g + i->m_cost;
00362 int target = i->m_target;
00363 const AStarNode* targetAStarNode = findNode(target);
00364 if (targetAStarNode != 0)
00365 {
00366 if (newg >= targetAStarNode->m_g)
00367 continue;
00368 if (! m_open.remove(target))
00369 m_closed.remove(target);
00370 }
00371 int newHeuristic = m_env->getHeuristic(target, m_target);
00372 AStarNode newAStarNode(target, node.m_nodeId, newg,
00373 newHeuristic);
00374 m_open.insert(newAStarNode);
00375 }
00376 m_closed.add(node);
00377
00378 }
00379 }
00380
00381 template<class MARKER, class CLOSED>
00382 void AStar<MARKER, CLOSED>::finishSearch(int start, const AStarNode& node)
00383 {
00384 m_closed.add(node);
00385 m_path = m_closed.constructPath(start, m_target);
00386 m_pathCost = node.m_f;
00387 m_statistics.get("path_cost").add(m_pathCost);
00388 }
00389
00390 template<class MARKER, class CLOSED>
00391 AStarNode AStar<MARKER, CLOSED>::getBestNodeFromOpen()
00392 {
00393 assert(! m_open.isEmpty());
00394 AStarNode result = m_open.pop();
00395 int nodeId = result.m_nodeId;
00396 assert(nodeId >= 0);
00397 ++m_nodesVisited;
00398 m_visitedNodes[nodeId] = '+';
00399 return result;
00400 }
00401
00402 template<class MARKER, class CLOSED>
00403 const StatisticsCollection& AStar<MARKER, CLOSED>::getStatistics() const
00404 {
00405 return m_statistics;
00406 }
00407
00408 template<class MARKER>
00409 AStarClosedLookup<MARKER>::AStarClosedLookup()
00410 {
00411 m_maxNodeId = 0;
00412 init(0);
00413 }
00414
00415 template<class MARKER>
00416 void AStarClosedLookup<MARKER>::add(const AStarNode& node)
00417 {
00418 int nodeId = node.m_nodeId;
00419 assert(nodeId >= 0);
00420 assert(nodeId < m_maxNodeId);
00421 assert(m_marker.get(nodeId) == false);
00422 m_marker.set(nodeId);
00423 m_nodes[nodeId] = node;
00424 }
00425
00426 template<class MARKER>
00427 vector<int> AStarClosedLookup<MARKER>::constructPath(int start, int target)
00428 {
00429 vector<int> result;
00430 int nodeId = target;
00431 while (true)
00432 {
00433 result.push_back(nodeId);
00434 if (nodeId == start)
00435 break;
00436 const AStarNode* node = search(nodeId);
00437 assert(node != 0);
00438 nodeId = node->m_parent;
00439 }
00440 assert(result.size() > 0);
00441 assert(*result.begin() == target);
00442 assert(*(result.end() - 1) == start);
00443 return result;
00444 }
00445
00446 template<class MARKER>
00447 void AStarClosedLookup<MARKER>::init(int maxNodeId)
00448 {
00449 assert(maxNodeId >= 0);
00450 m_nodes.resize(maxNodeId);
00451 m_marker.init(maxNodeId);
00452 m_maxNodeId = maxNodeId;
00453 }
00454
00455 template<class MARKER>
00456 void AStarClosedLookup<MARKER>::remove(int nodeId)
00457 {
00458 assert(nodeId >= 0);
00459 assert(nodeId < m_maxNodeId);
00460 assert(m_marker.get(nodeId) == true);
00461 m_marker.unset(nodeId);
00462 }
00463
00464 template<class MARKER>
00465 const AStarNode* AStarClosedLookup<MARKER>::search(int nodeId) const
00466 {
00467 assert(nodeId >= 0);
00468 assert(nodeId < m_maxNodeId);
00469 if (! m_marker.get(nodeId))
00470 return 0;
00471 const AStarNode* result = &m_nodes[nodeId];
00472 return result;
00473 }
00474
00475 template<class MARKER>
00476 AStarOpen<MARKER>::AStarOpen()
00477 {
00478 init(0);
00479 }
00480
00481 template<class MARKER>
00482 void AStarOpen<MARKER>::init(int numberNodes)
00483 {
00484 m_marker.init(numberNodes);
00485 m_lookupTable.resize(numberNodes);
00486 m_numberNodes = numberNodes;
00487 m_nodes.clear();
00488 }
00489
00490 template<class MARKER>
00491 void AStarOpen<MARKER>::insert(const AStarNode& node)
00492 {
00493 int nodeId = node.m_nodeId;
00494 assert(nodeId < m_numberNodes);
00495 assert(m_marker.get(nodeId) == false);
00496 m_marker.set(nodeId);
00497 NodeSetIterator pos = m_nodes.insert(node);
00498 m_lookupTable[nodeId] = pos;
00499 }
00500
00501 template<class MARKER>
00502 AStarNode AStarOpen<MARKER>::pop()
00503 {
00504 assert(! isEmpty());
00505 AStarNode result = *(m_nodes.begin());
00506 m_nodes.erase(m_nodes.begin());
00507 int nodeId = result.m_nodeId;
00508 assert(nodeId < m_numberNodes);
00509 assert(m_marker.get(nodeId) == true);
00510 m_marker.unset(nodeId);
00511 return result;
00512 }
00513
00514 template<class MARKER>
00515 void AStarOpen<MARKER>::print(ostream& ostrm) const
00516 {
00517 ostrm << "Open {\n";
00518 for (NodeSetConstIterator i = m_nodes.begin(); i != m_nodes.end(); ++i)
00519 {
00520 i->print(ostrm);
00521 ostrm << '\n';
00522 }
00523 ostrm << "}\n";
00524 }
00525
00526 template<class MARKER>
00527 bool AStarOpen<MARKER>::remove(int nodeId)
00528 {
00529 assert(nodeId >= 0);
00530 assert(nodeId < m_numberNodes);
00531 if (! m_marker.get(nodeId))
00532 return false;
00533 NodeSetIterator pos = m_lookupTable[nodeId];
00534 m_nodes.erase(pos);
00535 m_marker.unset(nodeId);
00536 return true;
00537 }
00538
00539 template<class MARKER>
00540 const AStarNode* AStarOpen<MARKER>::search(int nodeId) const
00541 {
00542 assert(nodeId >= 0);
00543 assert(nodeId < m_numberNodes);
00544 if (m_marker.get(nodeId))
00545 return &(*m_lookupTable[nodeId]);
00546 return 0;
00547 }
00548
00549 }
00550
00551
00552
00553 #endif