Advertisement
Guest User

Wegfindung mit A*

a guest
Jan 10th, 2011
87
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.15 KB | None | 0 0
  1. #include "shortest_path.hpp"
  2.  
  3. #include <set>
  4. #include <unordered_set>
  5. #include <array>
  6. #include <cassert>
  7.  
  8. typedef sf::Vector2i vec;   // sf::Vector2i hat die ints x und y als Member
  9. typedef unsigned f_t;
  10. typedef std::vector<std::vector<bool> > map_t;
  11. typedef std::list<vec> short_path_result_t;
  12.  
  13. struct Node
  14. {
  15.     Node(vec pos_, const Node* parent_, f_t g_, f_t h_): pos(pos_), parent(parent_), g(g_), h(h_) { }
  16.     Node(vec pos_): pos(pos_) { }   // Alles außer pos bleibt uninitalisiert!
  17.     bool operator< (const Node& rhs) const  { return f() < rhs.f(); }
  18.     bool operator== (const Node& rhs) const { return pos == rhs.pos;  }
  19.     f_t f() const                           { return g + h; }
  20.  
  21.     vec pos;
  22.     const Node* parent;
  23.     f_t g, h;
  24. };
  25.  
  26. namespace std {
  27. template<>
  28. struct hash<vec>
  29. {
  30.     std::size_t operator() (const vec& v) const
  31.     {
  32.         static const std::hash<int> hash_impl;
  33.         return hash_impl((v.x << 16) + v.y);
  34.     }
  35. };
  36. }
  37.  
  38. namespace std {
  39. template<>
  40. struct hash<Node>
  41. {
  42.     std::size_t operator() (const Node& v) const
  43.     {
  44.         static const std::hash<vec> hash_impl;
  45.         return hash_impl(v.pos);
  46.     }
  47. };
  48. }
  49.  
  50. namespace std {
  51. template<>
  52. struct hash<std::pair<const vec*, std::multiset<Node>::const_iterator> >
  53. {
  54.     std::size_t operator() (const std::pair<const vec*, std::multiset<Node>::const_iterator> nd) const
  55.     {
  56.         static const std::hash<vec> hash_impl;
  57.         return hash_impl(*nd.first);
  58.     }
  59. };
  60. }
  61.  
  62.  
  63. inline unsigned calc_h(vec from, vec to)
  64. {
  65.     const vec d = to - from;
  66.     return (abs(d.x) + abs(d.y)) * 10;
  67. }
  68.  
  69. const short_path_result_t walk_back(const Node* last)
  70. {
  71.     short_path_result_t result;
  72.     while (last != nullptr)
  73.     {
  74.         result.push_front(last->pos);
  75.         last = last->parent;
  76.     }
  77.     return result;
  78. }
  79.  
  80. const short_path_result_t shortest_path(const vec from, const vec to, const map_t& map, const bool walkable_val)
  81. {
  82.     if (map[from.x][from.y] != walkable_val || map[to.x][to.y] != walkable_val)
  83.         return short_path_result_t();
  84.  
  85.     typedef std::unordered_set<Node> closed_t;  // Sortiert nach Position
  86.     typedef std::multiset<Node> open_t;         // Sortiert nach f-Wert
  87.  
  88.     closed_t closed;
  89.     open_t open;
  90.  
  91.     open.insert(Node(from, nullptr, 0, calc_h(from, to)));
  92.  
  93.     while (!open.empty())
  94.     {
  95.         // Wähle Knoten mit bestem f aus offenen aus und verschiebe ihn zu den geschlossenen.
  96.         const std::pair<closed_t::const_iterator, bool> ins_res =
  97.             closed.insert(*open.begin());
  98.         assert(ins_res.second);
  99.         open.erase(open.begin());
  100.         const Node& cur = *ins_res.first;
  101.  
  102.         if (cur.pos == to) return walk_back(&cur);
  103.  
  104.         typedef std::tr1::array<vec, 8> dirs_t;
  105.         static const dirs_t dirs = {vec( 0, +1), vec(+1,  0), vec( 0, -1), vec(-1,  0),     // orthogonal; g = 10
  106.                                     vec(+1, +1), vec(+1, -1), vec(-1, +1), vec(-1, -1)};    // diagonal;   g = 14
  107.         for (dirs_t::size_type i = 0; i < dirs.size(); ++i)
  108.         {
  109.             const vec next_pos = cur.pos + dirs[i];
  110.  
  111.             // Ist next_pos begehbar & vorhanden?
  112.             if (next_pos.x >= 0 && next_pos.y >= 0 &&
  113.                 next_pos.x < map.size() && next_pos.y < map.front().size() &&
  114.                 map[next_pos.x][next_pos.y] == walkable_val && (
  115.                     i < 4 || (
  116.                         map[next_pos.x][cur.pos.y] == walkable_val &&
  117.                         map[cur.pos.x][next_pos.y] == walkable_val
  118.                     )
  119.                 ) && closed.find(Node(next_pos)) == closed.end() // Ist next_pos bereits geschlosssen?
  120.             )
  121.             {      
  122.                 const Node next(next_pos, &cur, cur.g + (i < 4 ? 10 : 14), calc_h(next_pos, to));
  123.  
  124.                 const open_t::const_iterator it = std::find_if(
  125.                     open.begin(), open.end(),
  126.                     [next_pos](const open_t::value_type& val) { return val.pos == next_pos; }
  127.                 );
  128.  
  129.                 // Ist next_pos bereits geöffnet?
  130.                 if (it != open.end())
  131.                 {
  132.                     // Ist dieser Weg zu next_pos besser, als der bisherige?
  133.                     if (next.g < it->g)
  134.                     {
  135.                         // Wenn, ja parent zu &cur ändern, und g neu berechnen (oben geschehen).
  136.                         open.erase(it);
  137.                         open.insert(next);
  138.                     }
  139.                 }
  140.                 // Wenn next_pos neu entdeckt wurde, d.h nicht geöffnet, geschlossen oder unbegehbar ist:
  141.                 else
  142.                 {
  143.                     open.insert(next);
  144.                 }
  145.             }   // if (vorhanden & begehbar)
  146.         }   // for (dirs)
  147.     }   // while (!open.empty)
  148.     return short_path_result_t();   // Keine geöffnenten Knoten mehr und to nicht gefunden: Rückgabe ist leerer Pfad.
  149. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement