/// <summary> /// The GenerateNewMaze method is called to generate a new maze. /// </summary> /// <returns></returns> public async Task GenerateNewMaze() { try { if (CanGenerateMaze) { MazeState = MazeState.MazeGenerating; // Clear the maze and stack. ResetMaze(); _mazeGeneratorStack = new Stack <MazeCell>(); // Select a random cell to start. MazeCell startCell = ChooseRandomCell(); startCell.CellState = CellState.Visited; // Generate the new maze. await GenerateNewMaze(startCell); // Set the start/end cells. if (MazeCells.Count > 0) { MazeCells.First().CellType = CellType.Start; MazeCells.Last().CellType = CellType.End; } MazeState = MazeState.MazeGenerated; } } catch (Exception ex) { throw new Exception("Maze.GenerateNewMaze(): " + ex.ToString()); } }
/// <summary> /// The GenerateNewMaze method is called to generate a new maze. /// The Randomized Prim's algorithm is used to generate the maze. /// https://en.wikipedia.org/wiki/Maze_generation_algorithm#Randomized_Prim's_algorithm /// </summary> /// <returns></returns> public async Task GenerateNewMaze() { try { if (CanGenerateMaze) { ResetMaze(); // Clear the maze. SimulationState = SimulationState.MazeGenerating; // Update the simulation state. List <MazeCell> frontierCells = new List <MazeCell>(); // Create a collection of maze walls. // Select a random cell to start. MazeCell initialCell = ChooseRandomCell(); initialCell.CellType = CellType.Passage; frontierCells.AddRange(RetrieveFrontierNeighbours(initialCell)); // Add the neighbouring cells to the frontier. while (frontierCells.Count > 0) { // Choose a random cell from the frontier. MazeCell currentCell = frontierCells.ElementAt(_randomNumberGenerator.Next(frontierCells.Count)); frontierCells.Remove(currentCell); // Remove this cell from the frontier. if (currentCell.CellType == CellType.Passage) { // If the cell is already a passage, move on to the next frontier cell. continue; } // Retrieve the "passage" neighbours for the current cell (these neighbours are already part of the maze). List <MazeCell> passageNeighbours = RetrievePassageNeighbours(currentCell); if (passageNeighbours.Count > 0) { // Select a random "passage" neighbour. MazeCell selectedNeighbour = passageNeighbours.ElementAt(_randomNumberGenerator.Next(passageNeighbours.Count)); // Connect the current cell to the selected neighbour. ConnectCells(currentCell, selectedNeighbour); currentCell.CellType = CellType.Passage; // Retrieve the frontier neighbours for the current cell, and add them to the frontier. frontierCells.AddRange(RetrieveFrontierNeighbours(currentCell)); } await Task.Delay(Constants.MazeGenerationDelayMilliSeconds); } // Set the start/end cells. MazeCell startCell = MazeCells.First(x => x.CellType == CellType.Passage); startCell.CellRole = CellRole.Start; MazeCell endCell = MazeCells.Last(x => x.CellType == CellType.Passage); endCell.CellRole = CellRole.End; // Place the robot at the start cell. _robot.SetLocation(startCell); SimulationState = SimulationState.MazeGenerated; // Update the simulation state. } } catch (Exception ex) { throw new Exception("Maze.GenerateNewMaze(): " + ex.ToString()); } }