Example #1
0
        /// <summary>
        /// The SimulationTimerEventHandler method is called when the simulation timer expires.
        /// It updates the current state of the simulation.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SimulationTimerEventHandler(object sender, EventArgs e)
        {
            try
            {
                if (SimulationState == SimulationState.Running)
                {
                    MazeCell robotLocation = MazeCells.First(x => x.ContainsRobot); // Retrieve the current location of the robot.
                    int      cellIndex     = MazeCells.IndexOf(robotLocation);      // Retrieve the index of the cell.

                    // Determine the indexes for the cell's neighbours.
                    int northNeighbourIndex = cellIndex - MazeWidthHeightCells;
                    int eastNeighbourIndex  = cellIndex + 1;
                    int southNeighbourIndex = cellIndex + MazeWidthHeightCells;
                    int westNeighbourIndex  = cellIndex - 1;

                    // Determine if the cell is on the north/east/south/west edge of the maze - certain neighbours must be ignored if the current cell is on an edge.
                    bool northEdge = cellIndex < MazeWidthHeightCells ? true : false;
                    bool eastEdge  = ((cellIndex + 1) % MazeWidthHeightCells) == 0 ? true : false;
                    bool westEdge  = (cellIndex % MazeWidthHeightCells) == 0 ? true : false;
                    bool southEdge = (cellIndex + MazeWidthHeightCells) >= (MazeWidthHeightCells * MazeWidthHeightCells) ? true : false;

                    // Retrieve the cell's neighbours.
                    MazeCell northCell = null;
                    MazeCell eastCell  = null;
                    MazeCell southCell = null;
                    MazeCell westCell  = null;
                    // North cell.
                    if (!northEdge && IsCellIndexValid(northNeighbourIndex))
                    {
                        northCell = MazeCells[northNeighbourIndex];
                    }
                    // East cell.
                    if (!eastEdge && IsCellIndexValid(eastNeighbourIndex))
                    {
                        eastCell = MazeCells[eastNeighbourIndex];
                    }
                    // South cell.
                    if (!southEdge && IsCellIndexValid(southNeighbourIndex))
                    {
                        southCell = MazeCells[southNeighbourIndex];
                    }
                    // West cell.
                    if (!westEdge && IsCellIndexValid(westNeighbourIndex))
                    {
                        westCell = MazeCells[westNeighbourIndex];
                    }

                    // Create a maze segment at the robot's current location.
                    MazeSegment mazeSegment = new MazeSegment(robotLocation, northCell, eastCell, southCell, westCell);

                    _robot.Move(mazeSegment);   // Move the robot.

                    SimulationTime = SimulationTime.Add(TimeSpan.FromMilliseconds(Constants.DefaultStepIntervalMilliSeconds));
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Maze.SimulationTimerEventHandler(object sender, EventArgs e): " + ex.ToString());
            }
        }
Example #2
0
        /// <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());
            }
        }
Example #3
0
        /// <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());
            }
        }