dfs_generator.hxx
Go to the documentation of this file.
1 /*===========================================================================================================
2  *
3  * HUC - Hurna Core
4  *
5  * Copyright (c) Michael Jeulin-Lagarrigue
6  *
7  * Licensed under the MIT License, you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * https://github.com/Hurna/Hurna-Core/blob/master/LICENSE
11  *
12  * Unless required by applicable law or agreed to in writing, software distributed under the License is
13  * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and limitations under the License.
15  *
16  * The above copyright notice and this permission notice shall be included in all copies or
17  * substantial portions of the Software.
18  *
19  *=========================================================================================================*/
20 #ifndef MODULE_MAZE_DFSG_HXX
21 #define MODULE_MAZE_DFSG_HXX
22 
23 #include <DataStructures/grid.hxx>
24 
25 // STD
26 #include <random>
27 #include <stack>
28 
29 namespace huc
30 {
31  namespace maze
32  {
46  {
47  public:
49  { uint64_t rootDistance; };
50 
52  typedef Maze::Cell Cell;
53  typedef Maze::Point Point;
54 
55  std::unique_ptr<Maze> operator()(const uint32_t width, const uint32_t height,
56  const Point& startPoint = Point(0,0), const uint32_t seed = 0)
57  {
58  if (width < 1 || height < 1 || startPoint.x >= width || startPoint.y >= height)
59  return nullptr;
60 
61  auto maze(std::unique_ptr<Maze>(new Maze(width, height)));
62  std::mt19937 mt(seed); // Random generator - Mersenne Twister algorithm
63  std::stack<std::shared_ptr<Cell>> pathStack; // Keep track of the cell path
64 
65  // Create a stack to keep track of the path and add the starting cell within.
66  (*maze)[startPoint.x][startPoint.y]->info.rootDistance = 0;
67  (*maze)[startPoint.x][startPoint.y]->info.isVisited = true;
68  pathStack.push((*maze)[startPoint.x][startPoint.y]);
69 
70  // While there is cell within the stack
71  while (!pathStack.empty())
72  {
73  // Handle the Cell at the top of the stack
74  auto cell = pathStack.top();
75  pathStack.pop();
76 
77  // Get available neighbours and connect to them
78  auto neighbours = GetNeighbours(*maze, *cell.get());
79 
80  // Add them to the stack and select one to be processed next
81  if (!neighbours.empty())
82  {
83  // Randomly select a cell to be processed
84  auto randIdx = mt() % neighbours.size();
85 
86  // For each available cell we make a connection and push it into the stack of being processed
87  // Only the choosen item should be add to the top following a DFS strategy
88  for (uint8_t i = 0; i < neighbours.size(); ++i)
89  {
90  neighbours[i]->info.isVisited = true;
91  neighbours[i]->info.rootDistance = cell->info.rootDistance + 1;
92 
93  if (i != randIdx) pathStack.push(neighbours[i]);
94  }
95  pathStack.push(neighbours[randIdx]);
96 
97  // Connect cell with all neighbours
98  maze->Connect(cell, neighbours);
99  }
100  }
101 
102  return maze;
103  }
104 
105  private:
112  static std::vector<std::shared_ptr<Cell>> GetNeighbours(const Maze& maze, const Cell& cell)
113  {
114  std::vector<std::shared_ptr<Cell>> neighbours;
115  neighbours.reserve(4);
116 
117  const auto x = cell.x;
118  const auto y = cell.y;
119 
120  // Push left if available
121  if (static_cast<int>(x - 1) >= 0 && !maze[x-1][y]->info.isVisited)
122  neighbours.push_back(maze[x-1][y]);
123  // Push bottom if available
124  if (static_cast<int>(y - 1) >= 0 && !maze[x][y-1]->info.isVisited)
125  neighbours.push_back(maze[x][y-1]);
126  // Push top if available
127  if (x + 1 < maze.Width() && !maze[x+1][y]->info.isVisited)
128  neighbours.push_back(maze[x+1][y]);
129  // Push right if available
130  if (y + 1 < maze.Height() && !maze[x][y+1]->info.isVisited)
131  neighbours.push_back(maze[x][y+1]);
132 
133  return neighbours;
134  }
135  };
136  }
137 }
138 
139 #endif // MODULE_MAZE_DFSG_HXX
uint32_t Width() const
Definition: grid.hxx:192
const uint32_t y
Definition: grid.hxx:70
Grid< CellInfo > Maze
static std::vector< std::shared_ptr< Cell > > GetNeighbours(const Maze &maze, const Cell &cell)
std::unique_ptr< Maze > operator()(const uint32_t width, const uint32_t height, const Point &startPoint=Point(0, 0), const uint32_t seed=0)
uint32_t Height() const
Definition: grid.hxx:193
Point struct is a convenient struct use to represent a 2D point for a grid (index position)...
Definition: grid.hxx:56
const uint32_t x
Definition: grid.hxx:69