robot_api.cpp
Go to the documentation of this file.
1 #include "robot_api.hpp"
2 #include "Robot.hpp"
3 #include "RoboSim.hpp"
4 
5 #include <functional>
6 #include <list>
7 #include <map>
8 #include <unordered_map>
9 
10 using std::function;
11 using std::list;
12 using std::make_pair;
13 using std::multimap;
14 using std::unordered_map;
15 using std::vector;
16 
17 namespace robot_api
18 {
19  GridCell* RobotUtility::findNearestAlly(GridCell& origin, vector<vector<GridCell> >& grid)
20  {
21  auto path = findShortestPathInternal(origin, RoboSim::SimGridAllyDeterminant{origin}, [](const GridCell& ignored) { return true; }, grid);
22 
23  if(path.size()==0)
24  return NULL;
25  else
26  return *(--path.end());
27  }
28 
29  list<GridCell*> RobotUtility::findShortestPath(GridCell& origin, const GridCell& target, vector<vector<GridCell> >& grid)
30  {
31  return findShortestPathInternal(origin,[&target](const GridCell& maybeTarget)
32  {
33  //normal == would compare by value;
34  //this simulates Java's "same object" test
35  //I /think/ compare-by-value would work too here, but why risk it?
36  //This is probably faster, anyway.
37  return &maybeTarget==&target;
38  },
39  [](const GridCell& maybePassable)
40  {
41  return maybePassable.contents==EMPTY;
42  }, grid);
43  }
44 
45 /*TODO: Next up is findShortestPathInternal and the rest of the Robot class.
46  * After that, RoboSim class.
47  * In RoboSim class, you'll need some sort of preprocessor macro trickery
48  * to select the number of players and their classes at compile time.
49  */
50  list<GridCell*> RobotUtility::findShortestPathInternal(GridCell& origin, const function<bool(const GridCell&)>& isTarget, const function<bool(const GridCell&)>& isPassable, vector<vector<GridCell> >& grid)
51  {
52  //Offsets to handle incomplete world map
53  int x_offset = grid[0][0].x_coord;
54  int y_offset = grid[0][0].y_coord;
55 
56  //Structures to efficiently handle accounting
57  multimap<int,GridCell*> unvisited_nodes;
58  unordered_map<GridCell*,list<GridCell*> > current_costs;
59 
60  //Origin's shortest path is nothing
61  list<GridCell*> origin_path = {};
62 
63  //Initialize graph search with origin
64  current_costs[&origin] = origin_path;
65  unvisited_nodes.insert(make_pair(0,&origin));
66 
67  while(unvisited_nodes.size()!=0)
68  {
69  int our_cost;
70  GridCell* our_cell;
71  {
72  auto current_entry = unvisited_nodes.begin();
73  our_cost = current_entry->first;
74  our_cell = current_entry->second;
75  //Anonymous block because current_entry is dangling iterator after this
76  unvisited_nodes.erase(current_entry);
77  }
78 
79  list<GridCell*>& current_path = current_costs[our_cell];
80 
81  //If we are a destination, algorithm has finished: return our current path
82  if(isTarget(*our_cell))
83  return current_path;
84 
85  /*We are adjacent to up to 4 nodes, with
86  coordinates relative to ours as follows:
87  (-1,0),(1,0),(0,-1),(0,1)*/
88  list<GridCell*> adjacent_nodes;
89  int gridX_value = our_cell->x_coord - x_offset;
90  int gridY_value = our_cell->y_coord - y_offset;
91  if(gridX_value!=0)
92  adjacent_nodes.push_back(&grid[gridX_value-1][gridY_value]);
93  if(gridX_value!=grid.size()-1)
94  adjacent_nodes.push_back(&grid[gridX_value+1][gridY_value]);
95  if(gridY_value!=0)
96  adjacent_nodes.push_back(&grid[gridX_value][gridY_value-1]);
97  if(gridY_value!=grid[0].size()-1)
98  adjacent_nodes.push_back(&grid[gridX_value][gridY_value+1]);
99 
100  /*Iterate over adjacent nodes, add to or update
101  entry in unvisited_nodes and current_costs if
102  necessary*/
103  for(GridCell* x : adjacent_nodes)
104  {
105  //If we're not passable, we can't be used as an adjacent cell, unless we're a target
106  if(!isPassable(*x) && !isTarget(*x))
107  continue;
108 
109  //Generate proposed path
110  list<GridCell*> x_proposed_path = current_path;
111  x_proposed_path.push_back(x);
112 
113  //current least cost path
114  if(current_costs.count(x))
115  {
116  list<GridCell*>& clcp = current_costs[x];
117  if(clcp.size()-1>our_cost+1)
118  {
119  auto old_range = unvisited_nodes.equal_range(clcp.size()-1);
120  for(auto i = old_range.first; i!=old_range.second; ++i)
121  if(i->second==x)
122  {
123  unvisited_nodes.erase(i);
124  break;
125  }
126  }
127  else
128  continue;
129  }
130 
131  unvisited_nodes.insert(make_pair(our_cost+1,x));
132  current_costs[x]=x_proposed_path;
133  }
134  }
135 
136  /*Loop is over, and we didn't find a path to the target :(
137  Return empty path.*/
138  return list<GridCell*>();
139  }
140 }
GridObject contents
Definition: robot_api.hpp:83
int x
Definition: test.cpp:1
static std::list< GridCell * > findShortestPathInternal(GridCell &origin, const std::function< bool(const GridCell &)> &isTarget, const std::function< bool(const GridCell &)> &isPassable, std::vector< std::vector< GridCell > > &grid)
Definition: robot_api.cpp:50
static std::list< GridCell * > findShortestPath(GridCell &origin, const GridCell &target, std::vector< std::vector< GridCell > > &grid)
Definition: robot_api.cpp:29
static GridCell * findNearestAlly(GridCell &origin, std::vector< std::vector< GridCell > > &grid)
Definition: robot_api.cpp:19