Advertisement
Cinestra

Pathfinder without DeadEnd Retracing

Apr 4th, 2023
69
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.21 KB | None | 0 0
  1. #include <iostream>
  2. #include <cassert>
  3. #include <queue>
  4. #include <stack>
  5. #include <string>
  6.  
  7. using namespace std;
  8.  
  9. class Coord
  10. {
  11. public:
  12. Coord(int r, int c) : m_row(r), m_col(c) {}
  13. int r() const { return m_row; }
  14. int c() const { return m_col; }
  15. private:
  16. int m_row;
  17. int m_col;
  18. };
  19.  
  20. // Returns true if a path exists from (starting_row, starting_col) to (ending_row, ending_col)
  21. bool pathExists(string maze[], int number_of_rows, int number_of_cols, int starting_row, int starting_col, int ending_row, int ending_col)
  22. {
  23. // Initialize a Queue of Coordinates
  24. queue<Coord> queue_of_coordinates;
  25.  
  26. // Push the Queue by putting in the starting row and starting col
  27. // Assignment instructions that starting point is always going to be a "." and not a wall
  28. queue_of_coordinates.push(Coord(starting_row, starting_col));
  29.  
  30. // The maze is an array of strings
  31. // While we have only defined the rows of the string, the "columns" of the string are implict because they are each of the individual characters of the string
  32. // We will overwrite that as D to mark it as discovered
  33. maze[starting_row][starting_col] = 'D';
  34.  
  35. while (!queue_of_coordinates.empty())
  36. {
  37. // Pop the queue by taking the coordinate in queue and popping it
  38. // Different from stack because stack pops the most recent item whereas queue pops the item that has been there the longest
  39. Coord current = queue_of_coordinates.front();
  40. queue_of_coordinates.pop();
  41.  
  42. const int current_row = current.r();
  43. const int current_col = current.c();
  44.  
  45. if (current_row == ending_row && current_col == ending_col)
  46. return true;
  47.  
  48. // Remember to use IF statements for the following, not else if statements
  49. // You need to put each and every possible point on the stack
  50.  
  51. // First, check EAST, which is (r, c+1)
  52. if (maze[current_row][current_col + 1] == '.')
  53. {
  54. queue_of_coordinates.push(Coord(current_row, current_col + 1));
  55. maze[current_row][current_col + 1] = 'D';
  56. }
  57.  
  58. // Second, check NORTH, which is (r-1, c)
  59. if (maze[current_row - 1][current_col] == '.')
  60. {
  61. queue_of_coordinates.push(Coord(current_row - 1, current_col));
  62. maze[current_row - 1][current_col] = 'D';
  63. }
  64.  
  65. // Third, check WEST, which is (r, c-1)
  66. if (maze[current_row][current_col - 1] == '.')
  67. {
  68. queue_of_coordinates.push(Coord(current_row, current_col - 1));
  69. maze[current_row][current_col - 1] = 'D';
  70. }
  71.  
  72. // Finally, check SOUTH, which is (r+1, c)
  73. if (maze[current_row + 1][current_col] == '.')
  74. {
  75. queue_of_coordinates.push(Coord(current_row + 1, current_col));
  76. maze[current_row + 1][current_col] = 'D';
  77. }
  78. }
  79.  
  80. return false;
  81. }
  82.  
  83. void printMaze(string maze[], int number_of_rows, int number_of_cols)
  84. {
  85. for (int i = 0; i < number_of_rows; i++)
  86. {
  87. for (int j = 0; j < number_of_cols; j++)
  88. {
  89. cout << maze[i][j];
  90. }
  91. cout << endl;
  92. }
  93.  
  94. cout << endl;
  95. }
  96.  
  97. bool mapDirections(string maze[], const int number_of_rows, const int number_of_cols, const int starting_row, const int starting_col, const int ending_row, const int ending_col)
  98. {
  99. /*
  100. * Psuedo Code Approach:
  101. * First run to check if the path even exists
  102. * Checking if the path exists marks each discoverable area as a D
  103. *
  104. * For this approach because we are checking individual paths, we will use a stack
  105. * We'll mark each point we retrace as R
  106. * Instead of popping coordinates whenever checking them at the top, we will keep them in the stack and only pop them when they lead nowhere
  107. * Instead of putting each direction possible on the stack, we will try pushing a single direction individually on the stack
  108. * If that single direction leads nowhere, we will mark it as N and then try the other directions
  109. *
  110. * We will denote a spot leading nowhere if there is no possible D to travel to that brings you to the start
  111. *
  112. * My intuition is to start from the end and go to the beginning because there are less paths to check initially
  113. */
  114.  
  115. // If a path exists, but it's because you do nothing, simply say do nothing
  116. if (starting_row == ending_row && starting_col == ending_col)
  117. {
  118. cout << "There are no directions because the start point is the same as the end point." << endl;
  119. return true;
  120. }
  121.  
  122. pathExists(maze, number_of_rows, number_of_cols, starting_row, starting_col, ending_row, ending_col);
  123. if (maze[ending_row][ending_col] != 'D')
  124. return false;
  125.  
  126. stack<Coord> stack_of_retraced_coords;
  127. stack_of_retraced_coords.push(Coord(ending_row, ending_col));
  128.  
  129. // Instead of popping coordinates after checking the top, we will actually keep them in the stack
  130. // We will pop coordinates when we reach a dead end or reach the beginning
  131. while (!stack_of_retraced_coords.empty())
  132. {
  133. Coord current = stack_of_retraced_coords.top();
  134.  
  135. const int current_row = current.r();
  136. const int current_col = current.c();
  137.  
  138. if (current_row == starting_row && current_col == starting_col)
  139. break;
  140.  
  141. maze[current_row][current_col] = 'R';
  142.  
  143. // Need to make sure that we actually are moving even if it isn't a dead end
  144. int has_moved = 0;
  145.  
  146. // First, check EAST, which is (r, c+1)
  147. if (maze[current_row][current_col + 1] == 'D')
  148. {
  149. stack_of_retraced_coords.push(Coord(current_row, current_col + 1));
  150. maze[current_row][current_col + 1] = 'R';
  151. has_moved++;
  152. }
  153.  
  154. // Second, check NORTH, which is (r-1, c)
  155. else if (maze[current_row - 1][current_col] == 'D')
  156. {
  157. stack_of_retraced_coords.push(Coord(current_row - 1, current_col));
  158. maze[current_row - 1][current_col] = 'R';
  159. has_moved++;
  160. }
  161.  
  162. // Third, check WEST, which is (r, c-1)
  163. else if (maze[current_row][current_col - 1] == 'D')
  164. {
  165. stack_of_retraced_coords.push(Coord(current_row, current_col - 1));
  166. maze[current_row][current_col - 1] = 'R';
  167. has_moved++;
  168. }
  169.  
  170. // Last, check SOUTH, which is (r+1, c)
  171. else if (maze[current_row + 1][current_col] == 'D')
  172. {
  173. stack_of_retraced_coords.push(Coord(current_row + 1, current_col));
  174. maze[current_row + 1][current_col] = 'R';
  175. has_moved++;
  176. }
  177.  
  178. if (has_moved == 0)
  179. {
  180. maze[current_row][current_col] = 'N';
  181. stack_of_retraced_coords.pop();
  182. }
  183. }
  184. return true;
  185. }
  186.  
  187. void verbalizeDirections(string maze[], int number_of_rows, int number_of_cols, int starting_row, int starting_col, int ending_row, int ending_col)
  188. {
  189. if (maze[ending_row][ending_col] != 'R')
  190. {
  191. cout << "Path is not solvable";
  192. return;
  193. }
  194.  
  195. if (starting_row == ending_row && starting_col == ending_col)
  196. {
  197. cout << "There are no directions because the start point is the same as the end point." << endl;
  198. return;
  199. }
  200.  
  201. cout << "Path is solvable, writing directions now: " << endl;
  202.  
  203. int current_row = starting_row;
  204. int current_col = starting_col;
  205.  
  206. // W denotes has walked
  207. maze[current_row][current_col] = 'W';
  208.  
  209. // !(a&&b) represents a NAND gate, meaning it only returns false if both A and B are true
  210. while (!(current_row == ending_row && current_col == ending_col))
  211. {
  212. if (maze[current_row][current_col + 1] == 'R')
  213. {
  214. maze[current_row][current_col + 1] = 'W';
  215. cout << "Walk to the East one space." << endl;
  216. current_col = current_col + 1;
  217. }
  218.  
  219. // Second, check NORTH, which is (r-1, c)
  220. else if (maze[current_row - 1][current_col] == 'R')
  221. {
  222. maze[current_row - 1][current_col] = 'W';
  223. cout << "Walk to the North one space." << endl;
  224. current_row = current_row - 1;
  225. }
  226.  
  227. // Third, check WEST, which is (r, c-1)
  228. else if (maze[current_row][current_col - 1] == 'R')
  229. {
  230. maze[current_row][current_col - 1] = 'W';
  231. cout << "Walk to the West one space." << endl;
  232. current_col = current_col - 1;
  233. }
  234.  
  235. // Last, check SOUTH, which is (r+1, c)
  236. else if (maze[current_row + 1][current_col] == 'R')
  237. {
  238. maze[current_row + 1][current_col] = 'W';
  239. cout << "Walk to the South one space." << endl;
  240. current_row = current_row + 1;
  241. }
  242. }
  243.  
  244. cout << "You have arrived at the end. " << endl;
  245. }
  246.  
  247. void findDirections(string maze[], int number_of_rows, int number_of_cols, int starting_row, int starting_col, int ending_row, int ending_col)
  248. {
  249. if (starting_row == ending_row && starting_col == ending_col)
  250. {
  251. cout << "There are no directions because the start is the same as the end" << endl;
  252. return;
  253. }
  254.  
  255. pathExists(maze, number_of_rows, number_of_cols, starting_row, starting_col, ending_row, ending_col);
  256.  
  257. if (maze[ending_row][ending_col] != 'D')
  258. {
  259. cout << "There are no directions because the maze is unsolvable";
  260. return;
  261. }
  262.  
  263. mapDirections(maze, number_of_rows, number_of_cols, starting_row, starting_col, ending_row, ending_col);
  264. verbalizeDirections(maze, number_of_rows, number_of_cols, starting_row, starting_col, ending_row, ending_col);
  265. }
  266.  
  267. int main()
  268. {
  269. string maze1[10] = {
  270. "XXXXXXXXXX",
  271. "X.X..X...X",
  272. "X.XX.X.XXX",
  273. "X....X.X.X",
  274. "XX.X.X...X",
  275. "XXX..X.X.X",
  276. "X...X...XX",
  277. "X.XX..X.XX",
  278. "X....X...X",
  279. "XXXXXXXXXX",
  280. };
  281.  
  282. string maze2[10] = {
  283. "XXXXXXXXXX",
  284. "X.X..X...X",
  285. "XXXX.X.XXX",
  286. "X....X.X.X",
  287. "XX.X.X...X",
  288. "XXX..X.X.X",
  289. "X...X...XX",
  290. "X.XX..X.XX",
  291. "X....X...X",
  292. "XXXXXXXXXX",
  293. };
  294.  
  295. string maze3[10] = {
  296. "XXXXXXXXXX",
  297. "XX.....XXX",
  298. "X..XX....X",
  299. "X...X...XX",
  300. "X.X.XXX..X",
  301. "XXXX..X..X",
  302. "XX....X..X",
  303. "X.......XX",
  304. "X..XXXXXXX",
  305. "XXXXXXXXXX",
  306. };
  307.  
  308. string maze4[10] = {
  309. "XXXXXXXXXX",
  310. "XX.....XXX",
  311. "X..XX....X",
  312. "X...X...XX",
  313. "X.X.XXX..X",
  314. "XXXX..X..X",
  315. "XX....X..X",
  316. "X.X.....XX",
  317. "X..XXXXXXX",
  318. "XXXXXXXXXX",
  319. };
  320.  
  321. string maze5[6] = {
  322. "XXXXXX",
  323. "XX.XXX",
  324. "XX.XXX",
  325. "X...XX",
  326. "XX.XXX",
  327. "XXXXXX",
  328. };
  329.  
  330. string maze6[10] = {
  331. "XXXXXXXXXX",
  332. "X.XXXXXXXX",
  333. "X...XXXX.X",
  334. "X.XXXXXX.X",
  335. "X.XXXXXX.X",
  336. "X.XXXXXX.X",
  337. "X.XXXXXX.X",
  338. "X.XXXXXX.X",
  339. "X........X",
  340. "XXXXXXXXXX",
  341. };
  342.  
  343. string maze7[10] = {
  344. "XXXXXXXXXX",
  345. "X....X...X",
  346. "X.XX.XX..X",
  347. "XXX....X.X",
  348. "X.XXX.XXXX",
  349. "X.X...X..X",
  350. "X...X.X..X",
  351. "XXXXX.X.XX",
  352. "X........X",
  353. "XXXXXXXXXX" };
  354.  
  355. cout << "Maze 5" << endl;
  356. pathExists(maze5, 6, 6, 4, 2, 1, 2);
  357. printMaze(maze5, 6, 6);
  358. mapDirections(maze5, 6, 6, 4, 2, 1, 2);
  359. printMaze(maze5, 6, 6);
  360. verbalizeDirections(maze5, 6, 6, 4, 2, 1, 2);
  361.  
  362. cout << "Maze 1" << endl;
  363. pathExists(maze1, 10, 10, 8, 6, 1, 1);
  364. printMaze(maze1, 10, 10);
  365. mapDirections(maze1, 10, 10, 8, 6, 1, 1);
  366. printMaze(maze1, 10, 10);
  367. verbalizeDirections(maze1, 10, 10, 8, 6, 1, 1);
  368.  
  369. cout << "Maze 6" << endl;
  370. pathExists(maze6, 10, 10, 8, 8, 1, 1);
  371. printMaze(maze6, 10, 10);
  372. mapDirections(maze6, 10, 10, 8, 8, 1, 1);
  373. printMaze(maze6, 10, 10);
  374. verbalizeDirections(maze6, 10, 10, 8, 8, 1, 1);
  375.  
  376. cout << "Maze 3" << endl;
  377. pathExists(maze3, 10, 10, 4, 3, 7, 1);
  378. printMaze(maze3, 10, 10);
  379. mapDirections(maze3, 10, 10, 4, 3, 7, 1);
  380. printMaze(maze3, 10, 10);
  381. verbalizeDirections(maze3, 10, 10, 4, 3, 7, 1);
  382.  
  383. cout << "Maze 7" << endl;
  384. pathExists(maze7, 10, 10, 3, 5, 8, 8);
  385. printMaze(maze7, 10, 10);
  386. findDirections(maze7, 10, 10, 3, 5, 8, 8);
  387. printMaze(maze7, 10, 10);
  388.  
  389. cout << "Maze 2" << endl;
  390. pathExists(maze2, 10, 10, 1, 1, 1, 3);
  391. findDirections(maze2, 10, 10, 1, 1, 1, 3);
  392. cout << endl;
  393.  
  394. cout << "Maze 2" << endl;
  395. pathExists(maze2, 10, 10, 1, 1, 1, 3);
  396. findDirections(maze2, 10, 10, 1, 1, 1, 1);
  397. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement