BWAPI
SPAR/AIModule/SparAIModule/PerceptualState/InfluenceMap/InfluenceMap.h
Go to the documentation of this file.
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 };
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines