Advertisement
Cinestra

Pathfinder Before Organizing it more

Apr 4th, 2023
30
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.93 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. void isDeadEndAfterRetrace(string maze[], const int starting_row, const int starting_col, const int ending_row, const int ending_col, const int current_row, const int current_col)
  98. {
  99. if (current_row == starting_row && current_col == starting_col)
  100. return;
  101.  
  102. if (current_row == ending_row && current_col == ending_col)
  103. return;
  104.  
  105. int number_of_directions_unavailable = 0;
  106.  
  107. // First, check EAST, which is (r, c+1)
  108. if (maze[current_row][current_col + 1] == '.' || maze[current_row][current_col + 1] == 'X' || maze[current_row][current_col + 1] == 'N' || maze[current_row][current_col + 1] == 'D')
  109. number_of_directions_unavailable++;
  110.  
  111. // Second, check NORTH, which is (r-1, c)
  112. if (maze[current_row - 1][current_col] == '.' || maze[current_row - 1][current_col] == 'X' || maze[current_row - 1][current_col] == 'N' || maze[current_row - 1][current_col] == 'D')
  113. number_of_directions_unavailable++;
  114.  
  115. // Third, check WEST, which is (r, c-1)
  116. if (maze[current_row][current_col - 1] == '.' || maze[current_row][current_col - 1] == 'X' || maze[current_row][current_col - 1] == 'N' || maze[current_row][current_col - 1] == 'D')
  117. number_of_directions_unavailable++;
  118.  
  119. // Last, check SOUTH, which is (r+1, c)
  120. if (maze[current_row + 1][current_col] == '.' || maze[current_row + 1][current_col] == 'X' || maze[current_row + 1][current_col] == 'N' || maze[current_row + 1][current_col] == 'D')
  121. number_of_directions_unavailable++;
  122.  
  123. if (number_of_directions_unavailable > 2)
  124. {
  125. maze[current_row][current_col] = 'N';
  126. return;
  127. }
  128.  
  129. return;
  130. }
  131.  
  132. 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)
  133. {
  134. /*
  135. * Psuedo Code Approach:
  136. * First run to check if the path even exists
  137. * Checking if the path exists marks each discoverable area as a D
  138. *
  139. * For this approach because we are checking individual paths, we will use a stack
  140. * We'll mark each point we retrace as R
  141. * 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
  142. * Instead of putting each direction possible on the stack, we will try pushing a single direction individually on the stack
  143. * If that single direction leads nowhere, we will mark it as N and then try the other directions
  144. *
  145. * We will denote a spot leading nowhere if there is no possible D to travel to that brings you to the start
  146. *
  147. * My intuition is to start from the end and go to the beginning because there are less paths to check initially
  148. */
  149.  
  150. // If a path exists, but it's because you do nothing, simply say do nothing
  151. if (starting_row == ending_row && starting_col == ending_col)
  152. {
  153. cout << "There are no directions because the start point is the same as the end point." << endl;
  154. return true;
  155. }
  156.  
  157. pathExists(maze, number_of_rows, number_of_cols, starting_row, starting_col, ending_row, ending_col);
  158. if (maze[ending_row][ending_col] != 'D')
  159. return false;
  160.  
  161. stack<Coord> stack_of_retraced_coords;
  162. stack_of_retraced_coords.push(Coord(ending_row, ending_col));
  163.  
  164. // Instead of popping coordinates after checking the top, we will actually keep them in the stack
  165. // We will pop coordinates when we reach a dead end or reach the beginning
  166. while (!stack_of_retraced_coords.empty())
  167. {
  168. Coord current = stack_of_retraced_coords.top();
  169.  
  170. const int current_row = current.r();
  171. const int current_col = current.c();
  172.  
  173. if (current_row == starting_row && current_col == starting_col)
  174. break;
  175.  
  176. maze[current_row][current_col] = 'R';
  177.  
  178. // Need to make sure that we actually are moving even if it isn't a dead end
  179. int has_moved = 0;
  180.  
  181. // First, check EAST, which is (r, c+1)
  182. if (maze[current_row][current_col + 1] == 'D')
  183. {
  184. stack_of_retraced_coords.push(Coord(current_row, current_col + 1));
  185. maze[current_row][current_col + 1] = 'R';
  186. has_moved++;
  187. }
  188.  
  189. // Second, check NORTH, which is (r-1, c)
  190. else if (maze[current_row - 1][current_col] == 'D')
  191. {
  192. stack_of_retraced_coords.push(Coord(current_row - 1, current_col));
  193. maze[current_row - 1][current_col] = 'R';
  194. has_moved++;
  195. }
  196.  
  197. // Third, check WEST, which is (r, c-1)
  198. else if (maze[current_row][current_col - 1] == 'D')
  199. {
  200. stack_of_retraced_coords.push(Coord(current_row, current_col - 1));
  201. maze[current_row][current_col - 1] = 'R';
  202. has_moved++;
  203. }
  204.  
  205. // Last, check SOUTH, which is (r+1, c)
  206. else if (maze[current_row + 1][current_col] == 'D')
  207. {
  208. stack_of_retraced_coords.push(Coord(current_row + 1, current_col));
  209. maze[current_row + 1][current_col] = 'R';
  210. has_moved++;
  211. }
  212.  
  213. if (has_moved == 0)
  214. {
  215. maze[current_row][current_col] = 'N';
  216. stack_of_retraced_coords.pop();
  217. }
  218. }
  219.  
  220. while (!stack_of_retraced_coords.empty())
  221. {
  222. Coord current = stack_of_retraced_coords.top();
  223. int current_row = current.r();
  224. int current_col = current.c();
  225. isDeadEndAfterRetrace(maze, starting_row, starting_col, ending_row, ending_col, current_row, current_col);
  226. stack_of_retraced_coords.pop();
  227. }
  228.  
  229. return true;
  230. }
  231.  
  232. void verbalizeDirections(string maze[], int number_of_rows, int number_of_cols, int starting_row, int starting_col, int ending_row, int ending_col)
  233. {
  234. if (maze[ending_row][ending_col] != 'R')
  235. {
  236. cout << "Path is not solvable";
  237. return;
  238. }
  239.  
  240. if (starting_row == ending_row && starting_col == ending_col)
  241. {
  242. cout << "There are no directions because the start point is the same as the end point." << endl;
  243. return;
  244. }
  245.  
  246. cout << "Path is solvable, writing directions now: " << endl;
  247.  
  248. int current_row = starting_row;
  249. int current_col = starting_col;
  250.  
  251. // W denotes has walked
  252. maze[current_row][current_col] = 'W';
  253.  
  254. // !(a&&b) represents a NAND gate, meaning it only returns false if both A and B are true
  255. while (!(current_row == ending_row && current_col == ending_col))
  256. {
  257. if (maze[current_row][current_col + 1] == 'R')
  258. {
  259. maze[current_row][current_col + 1] = 'W';
  260. cout << "Walk to the East one space." << endl;
  261. current_col = current_col + 1;
  262. }
  263.  
  264. // Second, check NORTH, which is (r-1, c)
  265. else if (maze[current_row - 1][current_col] == 'R')
  266. {
  267. maze[current_row - 1][current_col] = 'W';
  268. cout << "Walk to the North one space." << endl;
  269. current_row = current_row - 1;
  270. }
  271.  
  272. // Third, check WEST, which is (r, c-1)
  273. else if (maze[current_row][current_col - 1] == 'R')
  274. {
  275. maze[current_row][current_col - 1] = 'W';
  276. cout << "Walk to the West one space." << endl;
  277. current_col = current_col - 1;
  278. }
  279.  
  280. // Last, check SOUTH, which is (r+1, c)
  281. else if (maze[current_row + 1][current_col] == 'R')
  282. {
  283. maze[current_row + 1][current_col] = 'W';
  284. cout << "Walk to the South one space." << endl;
  285. current_row = current_row + 1;
  286. }
  287. }
  288.  
  289. cout << "You have arrived at the end. " << endl;
  290. }
  291.  
  292. void findDirections(string maze[], int number_of_rows, int number_of_cols, int starting_row, int starting_col, int ending_row, int ending_col)
  293. {
  294. if (starting_row == ending_row && starting_col == ending_col)
  295. {
  296. cout << "There are no directions because the start is the same as the end" << endl;
  297. return;
  298. }
  299.  
  300. pathExists(maze, number_of_rows, number_of_cols, starting_row, starting_col, ending_row, ending_col);
  301.  
  302. if (maze[ending_row][ending_col] != 'D')
  303. {
  304. cout << "There are no directions because the maze is unsolvable";
  305. return;
  306. }
  307.  
  308. mapDirections(maze, number_of_rows, number_of_cols, starting_row, starting_col, ending_row, ending_col);
  309. verbalizeDirections(maze, number_of_rows, number_of_cols, starting_row, starting_col, ending_row, ending_col);
  310. }
  311.  
  312. int main()
  313. {
  314. string maze1[10] = {
  315. "XXXXXXXXXX",
  316. "X.X..X...X",
  317. "X.XX.X.XXX",
  318. "X....X.X.X",
  319. "XX.X.X...X",
  320. "XXX..X.X.X",
  321. "X...X...XX",
  322. "X.XX..X.XX",
  323. "X....X...X",
  324. "XXXXXXXXXX",
  325. };
  326.  
  327. string maze2[10] = {
  328. "XXXXXXXXXX",
  329. "X.X..X...X",
  330. "XXXX.X.XXX",
  331. "X....X.X.X",
  332. "XX.X.X...X",
  333. "XXX..X.X.X",
  334. "X...X...XX",
  335. "X.XX..X.XX",
  336. "X....X...X",
  337. "XXXXXXXXXX",
  338. };
  339.  
  340. string maze3[10] = {
  341. "XXXXXXXXXX",
  342. "XX.....XXX",
  343. "X..XX....X",
  344. "X...X...XX",
  345. "X.X.XXX..X",
  346. "XXXX..X..X",
  347. "XX....X..X",
  348. "X.......XX",
  349. "X..XXXXXXX",
  350. "XXXXXXXXXX",
  351. };
  352.  
  353. string maze4[10] = {
  354. "XXXXXXXXXX",
  355. "XX.....XXX",
  356. "X..XX....X",
  357. "X...X...XX",
  358. "X.X.XXX..X",
  359. "XXXX..X..X",
  360. "XX....X..X",
  361. "X.X.....XX",
  362. "X..XXXXXXX",
  363. "XXXXXXXXXX",
  364. };
  365.  
  366. string maze5[6] = {
  367. "XXXXXX",
  368. "XX.XXX",
  369. "XX.XXX",
  370. "X...XX",
  371. "XX.XXX",
  372. "XXXXXX",
  373. };
  374.  
  375. string maze6[10] = {
  376. "XXXXXXXXXX",
  377. "X.XXXXXXXX",
  378. "X...XXXX.X",
  379. "X.XXXXXX.X",
  380. "X.XXXXXX.X",
  381. "X.XXXXXX.X",
  382. "X.XXXXXX.X",
  383. "X.XXXXXX.X",
  384. "X........X",
  385. "XXXXXXXXXX",
  386. };
  387.  
  388. string maze7[10] = {
  389. "XXXXXXXXXX",
  390. "X....X...X",
  391. "X.XX.XX..X",
  392. "XXX....X.X",
  393. "X.XXX.XXXX",
  394. "X.X...X..X",
  395. "X...X.X..X",
  396. "XXXXX.X.XX",
  397. "X........X",
  398. "XXXXXXXXXX" };
  399.  
  400. cout << "Maze 5" << endl;
  401. pathExists(maze5, 6, 6, 4, 2, 1, 2);
  402. printMaze(maze5, 6, 6);
  403. mapDirections(maze5, 6, 6, 4, 2, 1, 2);
  404. printMaze(maze5, 6, 6);
  405. verbalizeDirections(maze5, 6, 6, 4, 2, 1, 2);
  406.  
  407. cout << "Maze 1" << endl;
  408. pathExists(maze1, 10, 10, 8, 6, 1, 1);
  409. printMaze(maze1, 10, 10);
  410. mapDirections(maze1, 10, 10, 8, 6, 1, 1);
  411. printMaze(maze1, 10, 10);
  412. verbalizeDirections(maze1, 10, 10, 8, 6, 1, 1);
  413.  
  414. cout << "Maze 6" << endl;
  415. pathExists(maze6, 10, 10, 8, 8, 1, 1);
  416. printMaze(maze6, 10, 10);
  417. mapDirections(maze6, 10, 10, 8, 8, 1, 1);
  418. printMaze(maze6, 10, 10);
  419. verbalizeDirections(maze6, 10, 10, 8, 8, 1, 1);
  420.  
  421. cout << "Maze 3" << endl;
  422. pathExists(maze3, 10, 10, 4, 3, 7, 1);
  423. printMaze(maze3, 10, 10);
  424. mapDirections(maze3, 10, 10, 4, 3, 7, 1);
  425. printMaze(maze3, 10, 10);
  426. verbalizeDirections(maze3, 10, 10, 4, 3, 7, 1);
  427.  
  428. cout << "Maze 7" << endl;
  429. pathExists(maze7, 10, 10, 3, 5, 8, 8);
  430. printMaze(maze7, 10, 10);
  431. findDirections(maze7, 10, 10, 3, 5, 8, 8);
  432. printMaze(maze7, 10, 10);
  433.  
  434. cout << "Maze 2" << endl;
  435. pathExists(maze2, 10, 10, 1, 1, 1, 3);
  436. findDirections(maze2, 10, 10, 1, 1, 1, 3);
  437. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement