BWAPI
|
00001 #pragma once 00002 #include <functional> 00003 #include <set> 00004 #include <BWAPI.h> 00005 #include <utility> 00006 #include <queue> 00007 #include <bitset> 00008 #include <vector> 00009 #include <boost/unordered_set.hpp> 00010 #include <boost/dynamic_bitset.hpp> 00011 #include <boost/numeric/conversion/bounds.hpp> 00012 #include "../../Utils/Logger.h" 00013 00018 template<class InfluenceType> 00019 class InfluenceMap 00020 { 00021 public: 00028 InfluenceMap(size_t width, size_t height, BWAPI::Player* player 00029 ) 00030 : m_map(NULL) 00031 , m_width(width) 00032 , m_height(height) 00033 , m_player(player) 00034 { 00035 m_map = new InfluenceType[m_width*m_height]; 00036 } 00037 00038 ~InfluenceMap() 00039 { 00040 delete[] m_map; 00041 } 00042 00046 void update() 00047 { 00048 InfluenceType::update(*this); 00049 } 00050 00054 void display() const 00055 { 00056 // FIXME 00057 assert(m_width == BWAPI::Broodwar->mapWidth() 00058 && m_height == BWAPI::Broodwar->mapHeight()); 00059 00060 for (size_t y=0; y<m_height; ++y) 00061 { 00062 for (size_t x=0; x<m_width; ++x) 00063 { 00064 const InfluenceType& influence = getInfluence(x, y); 00065 influence.display(x*TILE_SIZE, y*TILE_SIZE, TILE_SIZE, TILE_SIZE, m_player); 00066 } 00067 } 00068 } 00069 00076 bool isValid(int x, int y) const 00077 { 00078 return is_between<int,true>(0, m_width - 1)(x) 00079 && is_between<int,true>(0, m_height - 1)(y); 00080 } 00081 00088 const InfluenceType& getInfluence(int x, int y) const 00089 { 00090 return _getInfluence(x, y); 00091 } 00092 00098 const InfluenceType& getInfluence(const BWAPI::Position& position) const 00099 { 00100 // FIXME 00101 assert(m_width == BWAPI::Broodwar->mapWidth() 00102 && m_height == BWAPI::Broodwar->mapHeight()); 00103 00104 return _getInfluence(position.x() / TILE_SIZE, position.y() / TILE_SIZE); 00105 } 00106 00110 void reset() 00111 { 00112 for(size_t i=0; i<m_width*m_height; ++i) 00113 { 00114 m_map[i].reset(); 00115 } 00116 } 00117 00123 void setInfluence(const BWAPI::Position& position, const InfluenceType& influence) 00124 { 00125 // FIXME 00126 assert(m_wdith == BWAPI::Broodwar->mapWidth() 00127 && m_height == BWAPI::Broodwar->mapHeight()); 00128 00129 InfluenceType& inf = _getInfluence(position.x() / TILE_SIZE, position.y() / TILE_SIZE); 00130 inf = influence; 00131 } 00132 00139 void setInfluence(int x, int y, const InfluenceType& influence) 00140 { 00141 InfluenceType& inf = _getInfluence(x, y); 00142 inf = influence; 00143 } 00144 00150 template<class Functor> 00151 Functor for_each(Functor functor) const 00152 { 00153 for (size_t y=0; y<m_height; ++y) 00154 for (size_t x=0; x<m_width; ++x) 00155 functor(x, y, *this); 00156 00157 return functor; 00158 } 00159 00160 //template<class Evaluator> 00161 //std::pair<int,int> hill_climbing(int x, int y, Evaluator evaluator, int maxSearchDepth = boost::numeric::bounds<int>::highest()) 00162 //{ 00163 // typedef std::pair<int,int> Pos; 00164 // 00165 // std::vector<Pos> succ; 00166 // succ.reserve(4); 00167 // while (maxSearchDepth-- > 0) 00168 // { 00169 // succ.clear(); 00170 // InfluenceMaps::detail::getAdjacentTiles(x, y, succ, *this, true); 00171 // 00172 // Evaluator::return_type minValue = evaluator(x, y, *this); 00173 // std::vector<Pos>::const_iterator minPos = succ.end(); 00174 // 00175 // for (std::vector<Pos>::const_iterator i=succ.begin(); i!=succ.end(); ++i) 00176 // { 00177 // Evaluator::return_type value = evaluator(i->first, i->second, *this); 00178 // if (value < minValue) 00179 // { 00180 // minValue = value; 00181 // minPos = i; 00182 // } 00183 // } 00184 // 00185 // if (minPos == succ.end()) 00186 // { 00187 // //SPAR_LOG(LogTypes::PERCEPTUAL_STATE, "[HILL CLIMBING] Reached local minimum (%d,%d)", x, y); 00188 // return std::make_pair(x, y); 00189 // } 00190 // else 00191 // { 00192 // x = minPos->first; 00193 // y = minPos->second; 00194 // } 00195 // } 00196 // 00197 // return std::make_pair(x, y); 00198 //} 00199 00203 size_t getWidth() const { return m_width; } 00204 00208 size_t getHeight() const { return m_height; } 00209 00213 const BWAPI::Player* const getPlayer() const { return m_player; } 00214 00215 private: 00216 template<class U> InfluenceMap(const InfluenceMap<U>&); 00217 template<class U> InfluenceMap& operator=(const InfluenceMap<U>&); 00218 InfluenceMap(const InfluenceMap<InfluenceType>&); 00219 InfluenceMap& operator=(const InfluenceMap<InfluenceType>&); 00220 00227 InfluenceType& _getInfluence(int x, int y) const 00228 { 00229 assert(isValid(x, y)); 00230 00231 return m_map[x + y*m_width]; 00232 } 00233 00234 typedef InfluenceType* matrix; // TODO replace by sparse matrix (SparseLib++?) 00235 matrix m_map; 00236 size_t m_width; 00237 size_t m_height; 00238 BWAPI::Player* m_player; 00239 }; 00240 00241 namespace InfluenceMaps 00242 { 00243 /**********************************************************************************************/ 00244 /* ALL */ 00245 /**********************************************************************************************/ 00246 namespace detail 00247 { 00248 typedef boost::tuples::null_type Nothing; 00249 00253 struct FunctorAdapter 00254 { 00255 template<class Functor, class T0> 00256 typename Functor::return_type operator()(Functor functor, int x, int y, const boost::tuple<const InfluenceMap<T0>&>& maps) const 00257 { 00258 return functor(x, y, maps.get<0>()); 00259 } 00260 00261 template<class Functor, class T0, class T1> 00262 typename Functor::return_type operator()(Functor functor, int x, int y, const boost::tuple<const InfluenceMap<T0>&, const InfluenceMap<T1>&>& maps) const 00263 { 00264 return functor(x, y, maps.get<0>(), maps.get<1>()); 00265 } 00266 00267 template<class Functor, class T0, class T1, class T2> 00268 typename Functor::return_type operator()(Functor functor, int x, int y, const boost::tuple<const InfluenceMap<T0>&, const InfluenceMap<T1>&, const InfluenceMap<T2>&>& maps) const 00269 { 00270 return functor(x, y, maps.get<0>(), maps.get<1>(), maps.get<2>()); 00271 } 00272 }; 00273 }; 00274 00275 /**********************************************************************************************/ 00276 /* BREADTH FIRST SEARCH */ 00277 /**********************************************************************************************/ 00278 namespace detail 00279 { 00289 template<class InfluenceType> 00290 void getAdjacentTiles(int x, int y, std::vector<std::pair<int,int>>& adj, const InfluenceMap<InfluenceType>& map, bool shuffle = false) 00291 { 00292 using ::std::make_pair; 00293 00294 static const int vx[] = {0, 0, -1, 1}; 00295 static const int vy[] = {-1, 1, 0, 0}; 00296 00297 for (int i=0; i<4; ++i) 00298 { 00299 if (map.isValid(x+vx[i], y+vy[i])) adj.push_back(make_pair(x+vx[i], y+vy[i])); 00300 } 00301 00302 if (shuffle) std::random_shuffle(adj.begin(), adj.end()); 00303 } 00304 00308 struct VectorOpenList 00309 { 00310 VectorOpenList(size_t w, size_t h) 00311 : m_w(w), m_vector(w*h, false) {} 00312 00313 bool contains(int x, int y) const 00314 { 00315 return m_vector[x + y*m_w]; 00316 } 00317 00318 void insert(int x, int y) 00319 { 00320 m_vector[x + y*m_w] = true; 00321 } 00322 00323 private: 00324 size_t m_w; 00325 std::vector<bool> m_vector; 00326 }; 00327 00328 template<size_t N> 00329 struct BitSetOpenList 00330 { 00331 BitSetOpenList(size_t w, size_t h) 00332 : m_w(w) 00333 { 00334 assert(m_bitset.size() >= w*h); 00335 } 00336 00337 bool contains(int x, int y) const 00338 { 00339 return m_bitset[x + y*m_w]; 00340 } 00341 00342 void insert(int x, int y) 00343 { 00344 m_bitset.set(x + y*m_w); 00345 } 00346 00347 private: 00348 size_t m_w; 00349 std::bitset<N> m_bitset; 00350 }; 00351 00352 struct DynamicBitSetOpenList 00353 { 00354 DynamicBitSetOpenList(size_t w, size_t h) 00355 : m_w(w), m_bitset(w * h) {} 00356 00357 bool contains(int x, int y) const 00358 { 00359 return m_bitset[x + y*m_w]; 00360 } 00361 00362 void insert(int x, int y) 00363 { 00364 m_bitset[x + y*m_w] = true; 00365 } 00366 00367 private: 00368 size_t m_w; 00369 boost::dynamic_bitset<> m_bitset; 00370 }; 00371 00372 template<class SetType> 00373 struct SetOpenList 00374 { 00375 SetOpenList(size_t w, size_t h) 00376 : m_w(w) {} 00377 00378 bool contains(int x, int y) const 00379 { 00380 return m_set.find(x + y*m_w) != m_set.end(); 00381 } 00382 00383 void insert(int x, int y) 00384 { 00385 m_set.insert(x + y*m_w); 00386 } 00387 00388 private: 00389 size_t m_w; 00390 SetType m_set; 00391 }; 00392 typedef SetOpenList<std::set<int>> StdSetOpenList; 00393 typedef SetOpenList<boost::unordered_set<int>> UnorderedSetOpenList; 00394 00395 // Choose open list implementation type 00396 // typedef VectorOpenList OpenListType; 00397 typedef BitSetOpenList<256*256> OpenListType; 00398 // typedef DynamicBitSetOpenList OpenListType; 00399 // typedef StdSetOpenList OpenListType; 00400 // typedef UnorderedSetOpenList OpenListType; 00401 00406 template<class GoalTest, class T0, class T1=Nothing, class T2=Nothing, class T3=Nothing> 00407 struct breadth_first_search 00408 { 00409 std::pair<int,int> operator()( 00410 int x, 00411 int y, 00412 GoalTest test, 00413 const boost::tuple< 00414 const InfluenceMap<typename T0>&, 00415 typename static_if_else< 00416 boost::is_same<typename T1,Nothing>::value, 00417 Nothing, 00418 const InfluenceMap<typename T1>&>::type, 00419 typename static_if_else< 00420 boost::is_same<typename T2,Nothing>::value, 00421 Nothing, 00422 const InfluenceMap<typename T2>&>::type, 00423 typename static_if_else< 00424 boost::is_same<typename T3,Nothing>::value, 00425 Nothing, 00426 const InfluenceMap<typename T3>&>::type 00427 >& maps) 00428 { 00429 FunctorAdapter functor; 00430 00431 using ::std::pair; 00432 using ::std::make_pair; 00433 00434 const InfluenceMap<typename T0>& map0 = maps.get<0>(); 00435 const size_t width = map0.getWidth(); 00436 const size_t height = map0.getHeight(); 00437 00438 ::std::queue<pair<int,int>> Q; 00439 OpenListType M(width, height); 00440 00441 pair<int,int> p(x,y); 00442 Q.push(p); 00443 M.insert(x, y); 00444 00445 unsigned long visited = 0L; 00446 00447 std::vector<pair<int,int>> succ; 00448 succ.reserve(4); 00449 00450 while(!Q.empty()) 00451 { 00452 const pair<int,int> v = Q.front(); 00453 int vx = v.first; 00454 int vy = v.second; 00455 Q.pop(); 00456 00457 ++visited; 00458 00459 if (functor(test, vx, vy, maps)) 00460 { 00461 x = vx; 00462 y = vy; 00463 break; 00464 } 00465 else 00466 { 00467 succ.clear(); 00468 getAdjacentTiles(vx, vy, succ, map0); // TODO Replace with functor? 00469 for (std::vector<pair<int,int>>::const_iterator i=succ.begin(); i!=succ.end(); ++i) 00470 { 00471 if (!M.contains(i->first, i->second)) 00472 { 00473 Q.push(*i); 00474 M.insert(i->first, i->second); 00475 } 00476 } 00477 } 00478 } 00479 00480 //SPAR_LOG(LogTypes::PERCEPTUAL_STATE, "[BREADTH FIRST SEARCH] No goal state found! %ul nodes visited, %ul nodes in list", visited, M.size()); 00481 return make_pair(x,y); 00482 } 00483 }; 00484 }; 00485 00494 template<class GoalTest, class T0> 00495 std::pair<int,int> breadth_first_search(int x, int y, GoalTest test, const InfluenceMap<T0>& map) 00496 { 00497 return InfluenceMaps::detail::breadth_first_search<GoalTest,T0>()( 00498 x, 00499 y, 00500 test, 00501 boost::tuple<const InfluenceMap<T0>&>(map)); 00502 } 00503 00513 template<class GoalTest, class T0, class T1> 00514 std::pair<int,int> breadth_first_search(int x, int y, GoalTest test, const InfluenceMap<T0>& map0, const InfluenceMap<T1>& map1) 00515 { 00516 assert(map0.getWidth() == map1.getWidth() && 00517 map0.getHeight() == map1.getHeight()); 00518 return InfluenceMaps::detail::breadth_first_search<GoalTest,T0,T1>()( 00519 x, 00520 y, 00521 test, 00522 boost::tuple< 00523 const InfluenceMap<T0>&, 00524 const InfluenceMap<T1>&>(map0, map1)); 00525 } 00526 00537 template<class GoalTest, class T0, class T1, class T2> 00538 std::pair<int,int> breadth_first_search(int x, int y, GoalTest test, const InfluenceMap<T0>& map0, const InfluenceMap<T1>& map1, const InfluenceMap<T2>& map2) 00539 { 00540 assert(map0.getWidth() == map1.getWidth() && 00541 map1.getWidth() == map2.getWidth() && 00542 map0.getHeight() == map1.getHeight() && 00543 map1.getHeight() == map2.getHeight()); 00544 return InfluenceMaps::detail::breadth_first_search<GoalTest,T0,T1>()( 00545 x, 00546 y, 00547 test, 00548 boost::tuple< 00549 const InfluenceMap<T0>&, 00550 const InfluenceMap<T1>&, 00551 const InfluenceMap<T2>&>(map0, map1, map2)); 00552 } 00553 00554 /**********************************************************************************************/ 00555 /* GRADIENT DESCENT */ 00556 /**********************************************************************************************/ 00557 namespace detail 00558 { 00563 template<class Gradient, class StopCriterion, class T0, class T1=Nothing, class T2=Nothing, class T3=Nothing> 00564 struct gradient_descent 00565 { 00566 std::pair<int,int> operator()( 00567 int x, 00568 int y, 00569 Gradient gradient, 00570 StopCriterion stop, 00571 const boost::tuple< 00572 const InfluenceMap<typename T0>&, 00573 typename static_if_else< 00574 boost::is_same<typename T1,Nothing>::value, 00575 Nothing, 00576 const InfluenceMap<typename T1>&>::type, 00577 typename static_if_else< 00578 boost::is_same<typename T2,Nothing>::value, 00579 Nothing, 00580 const InfluenceMap<typename T2>&>::type, 00581 typename static_if_else< 00582 boost::is_same<typename T3,Nothing>::value, 00583 Nothing, 00584 const InfluenceMap<typename T3>&>::type 00585 >& maps) 00586 { 00587 FunctorAdapter functor; 00588 00589 while (true) 00590 { 00591 std::pair<float,float> grad = functor(gradient, x, y, maps); 00592 00593 if (stop(grad)) break; 00594 00595 // TODO Replace with a line search algorithm 00596 bool ok = false; 00597 for (float step = 1.f; step > 0.f; step -= 0.0625f) 00598 { 00599 int nx = x - static_cast<int>(step * grad.first); 00600 int ny = y - static_cast<int>(step * grad.second); 00601 00602 if (maps.get<0>().isValid(nx, ny)) 00603 { 00604 x = nx; 00605 y = ny; 00606 ok = true; 00607 break; 00608 } 00609 } 00610 00611 if (!ok) break; 00612 } 00613 00614 //SPAR_LOG(LogTypes::PERCEPTUAL_STATE, "[GRADIENT DESCENT] Reached local minimum (%d,%d)", x, y); 00615 return std::make_pair(x, y); 00616 } 00617 }; 00618 }; 00619 00629 template<class Gradient, class StopCriterion, class T0> 00630 std::pair<int,int> gradient_descent(int x, int y, Gradient gradient, StopCriterion stop, const InfluenceMap<T0>& map0) 00631 { 00632 return InfluenceMaps::detail::gradient_descent<Gradient,StopCriterion,T0>()(x, y, gradient, stop, boost::tuple<const InfluenceMap<T0>&>(map0)); 00633 } 00634 00645 template<class Gradient, class StopCriterion, class T0, class T1> 00646 std::pair<int,int> gradient_descent(int x, int y, Gradient gradient, StopCriterion stop, const InfluenceMap<T0>& map0, const InfluenceMap<T1>& map1) 00647 { 00648 assert(map0.getWidth() == map1.getWidth() && 00649 map0.getHeight() == map1.getHeight()); 00650 return InfluenceMaps::detail::gradient_descent<Gradient,StopCriterion,T0,T1>()(x, y, gradient, stop, boost::tuple<const InfluenceMap<T0>&, const InfluenceMap<T1>&>(map0, map1)); 00651 } 00652 00664 template<class Gradient, class StopCriterion, class T0, class T1, class T2> 00665 std::pair<int,int> gradient_descent(int x, int y, Gradient gradient, StopCriterion stop, const InfluenceMap<T0>& map0, const InfluenceMap<T1>& map1, const InfluenceMap<T2>& map2) 00666 { 00667 assert(map0.getWidth() == map1.getWidth() && 00668 map1.getWidth() == map2.getWidth() && 00669 map0.getHeight() == map1.getHeight() && 00670 map1.getHeight() == map2.getHeight()); 00671 return InfluenceMaps::detail::gradient_descent<Gradient,StopCriterion,T0,T1,T2>()(x, y, gradient, stop, boost::tuple<const InfluenceMap<T0>&, const InfluenceMap<T1>&, const InfluenceMap<T2>&>(map0, map1, map2)); 00672 } 00673 };