Advertisement
Guest User

racetrack solver

a guest
Jul 6th, 2011
2,817
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.21 KB | None | 0 0
  1. #include <iostream>
  2. #include <vector>
  3. #include <map>
  4. #include <queue>
  5. #include <cassert>
  6.  
  7. using namespace std;
  8.  
  9. struct state {
  10. int x, y, dx, dy;
  11. };
  12.  
  13. ostream& operator<<(ostream& os, state const& s) {
  14. return os << "(" << s.x << ", " << s.y << ") (dx=" << s.dx << ", dy=" << s.dy << ")";
  15. }
  16.  
  17. struct solution {
  18. int nSteps;
  19. state s;
  20. };
  21.  
  22. typedef map<pair<int, int>, solution> mapIItoS;
  23.  
  24. vector<vector<mapIItoS> > v; // The s part points to the previous state.
  25. queue<solution> q;
  26.  
  27. int width, height;
  28. int goalX, goalY;
  29. int circleX, circleY, circleRadius;
  30. int nStatesSeen = 0;
  31.  
  32. // Assumes that the direction and length of the move would be valid if there
  33. // were no obstacles and we were on an infinite grid.
  34. //HACK: For now, we just check whether this move intersects a single user-provided circle.
  35. bool isMoveValid(state from, state to) {
  36. // return to.x >= 0 && to.x < width && to.y >= 0 && to.y < height;
  37. if (to.x < 0 || to.x >= width || to.y < 0 || to.y >= height) {
  38. return false;
  39. } else {
  40. if (circleRadius == -1) {
  41. return true; // No obstacle
  42. } else {
  43. // There's a circular obstacle.
  44. int dx = to.x - from.x;
  45. int dy = to.y - from.y;
  46.  
  47. if (!dx) {
  48. // Handle vertical lines specially.
  49. return to.x < circleX - circleRadius || to.x > circleX + circleRadius || max(to.y, from.y) < circleY - circleRadius || min(to.y, from.y) > circleY + circleRadius;
  50. } else {
  51. double m = (double) dy / dx; // Slope
  52. double c = (to.y - circleY) - m * (to.x - circleX); // Intercept, after translating so that circle is located at origin
  53. double discrim = circleRadius * circleRadius * (m * m + 1) - c * c;
  54.  
  55. if (discrim < 0) {
  56. return true; // Line does not intersect circle anywhere
  57. } else {
  58. double sqrtD = sqrt(discrim);
  59. double x1 = (-m * c - sqrtD) / (m * m + 1);
  60. if (x1 > max(to.x - circleX, from.x - circleX)) {
  61. return true; // Intersection occurs to the right of the line segment's end
  62. }
  63.  
  64. double x2 = (-m * c + sqrtD) / (m * m + 1);
  65. if (x2 < min(to.x - circleX, from.x - circleX)) {
  66. return true; // Intersection occurs to the left of the line segment's end
  67. }
  68.  
  69. return false; // Line either intersects or is totally contained.
  70. }
  71. }
  72. }
  73. }
  74. }
  75.  
  76. // This could be defined in several ways, but currently we simply have
  77. // a single target location, and we don't care about the velocity.
  78. bool isGoalState(state s) {
  79. return s.x == goalX && s.y == goalY;
  80. }
  81.  
  82. solution solve() {
  83. while (!q.empty()) {
  84. solution s(q.front());
  85. q.pop();
  86. ++nStatesSeen;
  87.  
  88. // Invariant: We already have an optimal path to s stored in v.
  89. assert(v[s.s.x][s.s.y].find(make_pair(s.s.dx, s.s.dy)) != v[s.s.x][s.s.y].end());
  90.  
  91. // Generate all valid moves we could make from here.
  92. for (int dy = -1; dy <= 1; ++dy) {
  93. for (int dx = -1; dx <= 1; ++dx) {
  94. solution ns;
  95. ns.s.dx = s.s.dx + dx;
  96. ns.s.dy = s.s.dy + dy;
  97. ns.s.x = s.s.x + ns.s.dx;
  98. ns.s.y = s.s.y + ns.s.dy;
  99. ns.nSteps = s.nSteps + 1;
  100. if (isMoveValid(s.s, ns.s)) {
  101. // If we haven't seen this new state before, then we have discovered
  102. // an optimal path to it.
  103. pair<int, int> newDxDy(make_pair(ns.s.dx, ns.s.dy));
  104. if (v[ns.s.x][ns.s.y].find(newDxDy) == v[ns.s.x][ns.s.y].end()) {
  105. solution tmp(s);
  106. ++tmp.nSteps;
  107. v[ns.s.x][ns.s.y][newDxDy] = tmp; // The s field points back to the previous state
  108.  
  109. if (isGoalState(ns.s)) {
  110. // We're done!
  111. return ns;
  112. }
  113.  
  114. q.push(ns);
  115. }
  116. }
  117. }
  118. }
  119. }
  120.  
  121. // We failed to find a path.
  122. solution s;
  123. s.nSteps = -1;
  124. return s;
  125. }
  126.  
  127. //HACK: For now we just have a totally empty grid of fixed size!
  128. void loadGrid() {
  129. width = 100;
  130. height = 100;
  131.  
  132. // Need to make the 2D matrix large enough
  133. v.resize(width, vector<mapIItoS>(height));
  134. }
  135.  
  136. int main(int argc, char **argv) {
  137. if (argc != 5 && argc != 8) {
  138. cerr << "Syntax: racetrack startX startY goalX goalY [circleX circleY radius]\n";
  139. return 1;
  140. }
  141.  
  142. int startX = atoi(argv[1]), startY = atoi(argv[2]);
  143. goalX = atoi(argv[3]);
  144. goalY = atoi(argv[4]);
  145.  
  146. loadGrid();
  147.  
  148. cout << "Starting at (" << startX << ", " << startY << ").\n";
  149. cout << "Goal is (" << goalX << ", " << goalY << ").\n";
  150. cout << "Grid size is " << width << "*" << height << " (W*H).\n";
  151.  
  152. if (argc == 8) {
  153. circleX = atoi(argv[5]);
  154. circleY = atoi(argv[6]);
  155. circleRadius = atoi(argv[7]);
  156. cout << "A circular obstacle of radius " << circleRadius << " is centred at (" << circleX << ", " << circleY << ").\n";
  157. } else {
  158. circleRadius = -1;
  159. cout << "No obstacle.\n";
  160. }
  161.  
  162. solution start;
  163. start.nSteps = 0;
  164. start.s.x = startX;
  165. start.s.y = startY;
  166. start.s.dx = 0;
  167. start.s.dy = 0;
  168. v[startX][startY][make_pair(0, 0)] = start;
  169.  
  170. q.push(start);
  171.  
  172. solution final = solve();
  173.  
  174. if (final.nSteps == -1) {
  175. cout << "No solution could be found!\n";
  176. } else {
  177. cout << final.nSteps << "-step solution:\n";
  178. solution cur(final);
  179. while (cur.nSteps) {
  180. cout << cur.s << "\n";
  181. cur = v[cur.s.x][cur.s.y][make_pair(cur.s.dx, cur.s.dy)];
  182. }
  183. }
  184.  
  185. cout << nStatesSeen << " states were examined in the process.\n";
  186. return 0;
  187. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement