Beafantles

Untitled

Mar 2nd, 2018
72
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.99 KB | None | 0 0
  1. #include <cstdint>
  2. #include <cstddef>
  3. #include <limits>
  4. #include <utility>
  5. #include <iostream>
  6. #include <string>
  7.  
  8. constexpr auto seed()
  9. {
  10. std::uint64_t shifted = 0;
  11.  
  12. for( const auto c : __TIME__ )
  13. {
  14. shifted <<= 8;
  15. shifted |= c;
  16. }
  17.  
  18. return shifted;
  19. }
  20.  
  21. struct PCG
  22. {
  23. struct pcg32_random_t { std::uint64_t state=0; std::uint64_t inc=seed(); };
  24. pcg32_random_t rng;
  25. typedef std::uint32_t result_type;
  26.  
  27. constexpr result_type operator()()
  28. {
  29. return pcg32_random_r();
  30. }
  31.  
  32. static result_type constexpr min()
  33. {
  34. return std::numeric_limits<result_type>::min();
  35. }
  36.  
  37. static result_type constexpr max()
  38. {
  39. return std::numeric_limits<result_type>::min();
  40. }
  41.  
  42. private:
  43. constexpr std::uint32_t pcg32_random_r()
  44. {
  45. std::uint64_t oldstate = rng.state;
  46. // Advance internal state
  47. rng.state = oldstate * 6364136223846793005ULL + (rng.inc|1);
  48. // Calculate output function (XSH RR), uses old state for max ILP
  49. std::uint32_t xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u;
  50. std::uint32_t rot = oldstate >> 59u;
  51. return (xorshifted >> rot) | (xorshifted << ((-rot) & 31));
  52. }
  53.  
  54. };
  55.  
  56. template<typename T, typename Gen>
  57. constexpr auto distribution(Gen &g, T min, T max)
  58. {
  59. const auto range = max - min + 1;
  60. const auto bias_remainder = std::numeric_limits<T>::max() % range;
  61. const auto unbiased_max = std::numeric_limits<T>::max() - bias_remainder - 1;
  62.  
  63. auto r = g();
  64. for (; r > unbiased_max; r = g());
  65.  
  66. return (r % range) + min;
  67. }
  68.  
  69.  
  70.  
  71.  
  72.  
  73. struct Cell
  74. {
  75. bool left_open = false;
  76. bool right_open = false;
  77. bool up_open = false;
  78. bool down_open = false;
  79. bool visited = false;
  80. };
  81.  
  82. template<typename Data, std::size_t Cols, std::size_t Rows>
  83. struct Array2D
  84. {
  85. constexpr static auto rows() { return Rows; }
  86. constexpr static auto cols() { return Cols; }
  87.  
  88. constexpr Data &operator()(const std::size_t col, const std::size_t row)
  89. {
  90. return m_data[col + (row * Cols)];
  91. }
  92.  
  93. constexpr const Data &operator()(const std::size_t col, const std::size_t row) const
  94. {
  95. return m_data[col + (row * Cols)];
  96. }
  97.  
  98. Data m_data[Cols * Rows];
  99. };
  100.  
  101. enum class WallType
  102. {
  103. Empty,
  104. UpperLeft,
  105. Vertical,
  106. Horizontal,
  107. UpperRight,
  108. LowerLeft,
  109. LowerRight,
  110. RightTee,
  111. LeftTee,
  112. UpTee,
  113. DownTee,
  114. FourWay,
  115. Up,
  116. Down,
  117. Left,
  118. Right,
  119. Visited,
  120. Used
  121. };
  122.  
  123. template<typename T, std::size_t Size>
  124. struct Stack
  125. {
  126. T m_data[Size]{};
  127. std::size_t pos = 0;
  128.  
  129. template<typename ... Arg>
  130. void constexpr emplace_back(Arg &&... arg)
  131. {
  132. m_data[pos] = T{std::forward<Arg>(arg)...};
  133. ++pos;
  134. }
  135.  
  136. constexpr T pop_back()
  137. {
  138. --pos;
  139. return m_data[pos];
  140. }
  141.  
  142. constexpr bool empty() const
  143. {
  144. return pos == 0;
  145. }
  146.  
  147. constexpr std::size_t size() const
  148. {
  149. return pos;
  150. }
  151. };
  152.  
  153. struct Loc
  154. {
  155. std::size_t col=0;
  156. std::size_t row=0;
  157.  
  158. constexpr Loc(const std::size_t t_col, const std::size_t t_row)
  159. : col(t_col), row(t_row)
  160. {
  161. }
  162.  
  163. constexpr Loc() = default;
  164. };
  165.  
  166. template<std::size_t num_cols, std::size_t num_rows>
  167. constexpr Array2D<Cell, num_cols, num_rows> make_maze()
  168. {
  169.  
  170. PCG pcg;
  171.  
  172. Array2D<Cell, num_cols, num_rows> M;
  173.  
  174.  
  175.  
  176. // Set starting row and column
  177. std::size_t c = 0;
  178. std::size_t r = 0;
  179. Stack<Loc, num_cols * num_rows> history;
  180. history.emplace_back(c,r); // The history is the stack of visited locations
  181.  
  182. // Trace a path though the cells of the maze and open walls along the path.
  183. // We do this with a while loop, repeating the loop until there is no history,
  184. // which would mean we backtracked to the initial start.
  185. while (!history.empty())
  186. {
  187. M(c, r).visited = true;
  188.  
  189. Stack<char, 4> check{};
  190.  
  191. // check if the adjacent cells are valid for moving to
  192. if (c > 0 && M(c-1, r).visited == false) {
  193. check.emplace_back('L');
  194. }
  195. if (r > 0 && M(c, r-1).visited == false) {
  196. check.emplace_back('U');
  197. }
  198. if (c < num_cols-1 && M(c+1, r).visited == false) {
  199. check.emplace_back('R');
  200. }
  201. if (r < num_rows-1 && M(c, r+1).visited == false) {
  202. check.emplace_back('D');
  203. }
  204.  
  205. if (!check.empty()) { // If there is a valid cell to move to.
  206. // Mark the walls between cells as open if we move
  207.  
  208. history.emplace_back(c,r);
  209.  
  210. for (auto num_pops = distribution(pcg, std::size_t(0), check.size() - 1); num_pops > 0; --num_pops)
  211. {
  212. check.pop_back();
  213. }
  214.  
  215. switch (check.pop_back()) {
  216. case 'L':
  217. M(c, r).left_open = true;
  218. --c;
  219. M(c, r).right_open = true;
  220. break;
  221.  
  222. case 'U':
  223. M(c, r).up_open = true;
  224. --r;
  225. M(c, r).down_open = true;
  226. break;
  227.  
  228. case 'R':
  229. M(c, r).right_open = true;
  230. ++c;
  231. M(c, r).left_open = true;
  232. break;
  233.  
  234. case 'D':
  235. M(c, r).down_open = true;
  236. ++r;
  237. M(c, r).up_open = true;
  238. break;
  239. }
  240. } else {
  241. // If there are no valid cells to move to.
  242. // retrace one step back in history if no move is possible
  243. const auto last = history.pop_back();
  244. c = last.col;
  245. r = last.row;
  246. }
  247. }
  248.  
  249. // Open the walls at the start and finish
  250. M(0,0).left_open = true;
  251. M(num_cols-1, num_rows-1).right_open = true;
  252.  
  253. return M;
  254. }
  255.  
  256. template<std::size_t num_cols, std::size_t num_rows>
  257. constexpr Array2D<WallType, num_cols*2+1, num_rows*2+1> render_maze(const Array2D<Cell, num_cols, num_rows> &maze_data)
  258. {
  259. Array2D<WallType, num_cols*2+1, num_rows*2+1> result{};
  260.  
  261.  
  262. for (std::size_t col = 0; col < num_cols; ++col)
  263. {
  264. for (std::size_t row = 0; row < num_rows; ++row)
  265. {
  266. const auto render_col = col * 2 + 1;
  267. const auto render_row = row * 2 + 1;
  268.  
  269. const auto &cell = maze_data(col, row);
  270.  
  271. // upper
  272. if (!cell.up_open) { result(render_col,render_row-1) = WallType::Horizontal; }
  273.  
  274. // left
  275. if (!cell.left_open) { result(render_col-1,render_row) = WallType::Vertical; }
  276.  
  277. // right
  278. if (!cell.right_open) { result(render_col+1,render_row) = WallType::Vertical; }
  279.  
  280. // lower
  281. if (!cell.down_open) { result(render_col,render_row+1) = WallType::Horizontal; }
  282. }
  283. }
  284.  
  285. for (std::size_t col = 0; col < result.cols(); col += 2)
  286. {
  287. for (std::size_t row = 0; row < result.rows(); row += 2)
  288. {
  289. const auto up = (row == 0)?false:result(col, row-1) != WallType::Empty;
  290. const auto left = (col == 0)?false:result(col-1, row) != WallType::Empty;
  291. const auto right = (col == num_cols * 2)?false:result(col+1, row) != WallType::Empty;
  292. const auto down = (row == num_rows * 2)?false:result(col, row+1) != WallType::Empty;
  293.  
  294. if (up && right && down && left) {
  295. result(col, row) = WallType::FourWay;
  296. }
  297. if (up && right && down && !left) {
  298. result(col, row) = WallType::RightTee;
  299. }
  300. if (up && right && !down && left) {
  301. result(col, row) = WallType::UpTee;
  302. }
  303. if (up && !right && down && left) {
  304. result(col, row) = WallType::LeftTee;
  305. }
  306. if (!up && right && down && left) {
  307. result(col, row) = WallType::DownTee;
  308. }
  309.  
  310. if (up && right && !down && !left) {
  311. result(col, row) = WallType::LowerLeft;
  312. }
  313. if (up && !right && !down && left) {
  314. result(col, row) = WallType::LowerRight;
  315. }
  316. if (!up && !right && down && left) {
  317. result(col, row) = WallType::UpperRight;
  318. }
  319. if (!up && right && down && !left) {
  320. result(col, row) = WallType::UpperLeft;
  321. }
  322. if (!up && right && !down && left) {
  323. result(col, row) = WallType::Horizontal;
  324. }
  325. if (up && !right && down && !left) {
  326. result(col, row) = WallType::Vertical;
  327. }
  328.  
  329.  
  330. if (up && !right && !down && !left) {
  331. result(col, row) = WallType::Up;
  332. }
  333. if (!up && right && !down && !left) {
  334. result(col, row) = WallType::Right;
  335. }
  336. if (!up && !right && down && !left) {
  337. result(col, row) = WallType::Down;
  338. }
  339. if (!up && !right && !down && left) {
  340. result(col, row) = WallType::Left;
  341. }
  342. }
  343. }
  344.  
  345.  
  346. return result;
  347. }
  348.  
  349. template<typename T>
  350. constexpr auto solve(T maze)
  351. {
  352. constexpr auto num_cols = maze.cols();
  353. constexpr auto num_rows = maze.rows();
  354.  
  355. size_t row = 1;
  356. size_t col = 0;
  357.  
  358. Stack<Loc, num_cols * num_rows> history;
  359.  
  360. history.emplace_back(col, row);
  361. while (row != maze.rows() - 2 || col != maze.cols() - 2)
  362. {
  363. maze(col, row) = WallType::Visited;
  364.  
  365. // check if the adjacent cells are valid for moving to
  366. if (col < num_cols-1 && maze(col+1, row) == WallType::Empty) {
  367. ++col;
  368. history.emplace_back(col, row);
  369. } else if (row < num_rows-1 && maze(col, row+1) == WallType::Empty) {
  370. ++row;
  371. history.emplace_back(col, row);
  372. } else if (col > 0 && maze(col-1, row) == WallType::Empty) {
  373. --col;
  374. history.emplace_back(col, row);
  375. } else if (row > 0 && maze(col, row-1) == WallType::Empty) {
  376. --row;
  377. history.emplace_back(col, row);
  378. } else {
  379. // If there are no valid cells to move to.
  380. // retrace one step back in history if no move is possible
  381. const auto last = history.pop_back();
  382. col = last.col;
  383. row = last.row;
  384. }
  385. }
  386.  
  387. while (!history.empty())
  388. {
  389. const auto last = history.pop_back();
  390. maze(last.col, last.row) = WallType::Used;
  391. }
  392.  
  393. return maze;
  394. }
  395.  
  396.  
  397. int main()
  398. {
  399. constexpr const std::size_t num_cols = 10;
  400. constexpr const std::size_t num_rows = 10;
  401.  
  402. constexpr auto maze = make_maze<num_cols, num_rows>();
  403. constexpr auto rendered_maze = solve(render_maze(maze));
  404.  
  405. for (std::size_t row = 0; row < num_rows*2+1; ++row)
  406. {
  407. for (std::size_t col = 0; col < num_cols*2+1; ++col)
  408. {
  409. const auto square = [&](){
  410. switch (rendered_maze(col, row)) {
  411. case WallType::Empty: return " ";
  412. case WallType::UpperLeft: return "┌";
  413. case WallType::Vertical: return "│";
  414. case WallType::Horizontal: return "─";
  415. case WallType::UpperRight: return "┐";
  416. case WallType::LowerLeft: return "└";
  417. case WallType::LowerRight: return "┘";
  418. case WallType::RightTee: return "├";
  419. case WallType::LeftTee: return "┤";
  420. case WallType::UpTee: return "┴";
  421. case WallType::DownTee: return "┬";
  422. case WallType::FourWay: return "┼";
  423. case WallType::Up: return "╵";
  424. case WallType::Down: return "╷";
  425. case WallType::Left: return "╴";
  426. case WallType::Right: return "╶";
  427. case WallType::Visited: return "·";
  428. case WallType::Used: return "*";
  429. default: throw 0;
  430. }
  431. }();
  432.  
  433. std::cout << square;
  434. }
  435. std::cout << '\n';
  436. }
  437. }
Add Comment
Please, Sign In to add comment