Exemplo n.º 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());
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// The RetrieveNeighbours method is called to retrieve the neighbour cells for the provided cell.
        /// The neighbour cells are "offset" cells from the provided cell, in all 4 directions.
        /// </summary>
        /// <param name="cell"></param>
        /// <returns></returns>
        private List <MazeCell> RetrieveNeighbours(MazeCell cell, int offset = 1)
        {
            try
            {
                if (cell == null)
                {
                    throw new Exception("cell can not be null.");
                }

                if (offset < 1)
                {
                    throw new Exception("offset must be greater than or equal to 1.");
                }

                int cellIndex = MazeCells.IndexOf(cell);   // Retrieve the index of the cell.

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

                // Determine if the current 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 current cell's neighbours.
                List <MazeCell> cellNeightbours = new List <MazeCell>();
                // North cell.
                if (!northEdge && IsCellIndexValid(northNeighbourIndex))
                {
                    cellNeightbours.Add(MazeCells[northNeighbourIndex]);
                }
                // East cell.
                if (!eastEdge && IsCellIndexValid(eastNeighbourIndex))
                {
                    cellNeightbours.Add(MazeCells[eastNeighbourIndex]);
                }
                // South cell.
                if (!southEdge && IsCellIndexValid(southNeighbourIndex))
                {
                    cellNeightbours.Add(MazeCells[southNeighbourIndex]);
                }
                // West cell.
                if (!westEdge && IsCellIndexValid(westNeighbourIndex))
                {
                    cellNeightbours.Add(MazeCells[westNeighbourIndex]);
                }

                return(cellNeightbours);
            }
            catch (Exception ex)
            {
                throw new Exception("Maze.RetrieveNeighbours(MazeCell cell): " + ex.ToString());
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// The ConnectCells method is called to connect two cells.
        /// The wall cell that exists between the two cells becomes a passage.
        /// </summary>
        /// <param name="cellOne"></param>
        /// <param name="cellTwo"></param>
        private void ConnectCells(MazeCell cellOne, MazeCell cellTwo)
        {
            try
            {
                if (cellOne == null)
                {
                    throw new Exception("cellOne can not be null.");
                }
                if (cellTwo == null)
                {
                    throw new Exception("cellTwo can not be null.");
                }

                int indexOne = MazeCells.IndexOf(cellOne);
                int indexTwo = MazeCells.IndexOf(cellTwo);

                if (!IsCellIndexValid(indexOne))
                {
                    throw new Exception("can not determine index for cellOne.");
                }
                if (!IsCellIndexValid(indexTwo))
                {
                    throw new Exception("can not determine index for cellTwo.");
                }

                int offset    = indexOne - indexTwo;
                int wallIndex = indexOne - (offset / 2);

                if (IsCellIndexValid(wallIndex))
                {
                    MazeCell wallCell = MazeCells[wallIndex];
                    wallCell.CellType = CellType.Passage;
                }
                else
                {
                    throw new Exception("unable to retireve cell between cellOne and cellTwo.");
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Maze.ConnectCells(MazeCell cellOne, MazeCell cellTwo): " + ex.ToString());
            }
        }
Exemplo n.º 4
0
        /// <summary>
        /// The IsCellOnTheEdge method is called to determine if the provided cell is on the edge of the maze grid.
        /// </summary>
        /// <param name="cell"></param>
        /// <returns></returns>
        private bool IsCellOnTheEdge(MazeCell cell)
        {
            try
            {
                if (cell == null)
                {
                    throw new Exception("cell can not be null.");
                }

                int cellIndex = MazeCells.IndexOf(cell);   // Retrieve the index of the cell.

                // Determine if the current cell is on the north/east/south/west edge of the maze.
                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;

                return(northEdge || eastEdge || westEdge || southEdge);
            }
            catch (Exception ex)
            {
                throw new Exception("Maze.IsCellOnTheEdge(MazeCell cell): " + ex.ToString());
            }
        }
Exemplo n.º 5
0
        /// <summary>
        /// The GenerateNewMaze method is called to generate a new maze.
        /// The Recursive Backtracker algorithm is used to generate the maze.
        /// http://weblog.jamisbuck.org/2010/12/27/maze-generation-recursive-backtracking
        /// https://en.wikipedia.org/wiki/Maze_generation_algorithm#Recursive_backtracker
        /// </summary>
        private async Task GenerateNewMaze(MazeCell currentCell)
        {
            try
            {
                await Task.Delay(Constants.MazeGenerationDelayMilliSeconds);

                if (MazeCells.Any(x => x.CellState == CellState.Default) || _mazeGeneratorStack.Count > 0) // The maze contains unvisited cells or the stack is not empty.
                {
                    int cellIndex = MazeCells.IndexOf(currentCell);                                        // Retrieve the index of the current cell.

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

                    // Determine if the current 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 < Constants.MazeWidth ? true : false;
                    bool eastEdge  = ((cellIndex + 1) % Constants.MazeWidth) == 0 ? true : false;
                    bool westEdge  = (cellIndex % Constants.MazeWidth) == 0 ? true : false;
                    bool southEdge = (cellIndex + Constants.MazeWidth) >= (Constants.MazeWidth * Constants.MazeHeight) ? true : false;

                    // Retrieve the current cell's unvisited neighbours.
                    List <MazeCell> unvisitedNeighbours = new List <MazeCell>();
                    // North cell.
                    if (!northEdge && IsCellIndexValid(northNeighbourIndex) && MazeCells[northNeighbourIndex].CellState == CellState.Default)
                    {
                        unvisitedNeighbours.Add(MazeCells[northNeighbourIndex]);
                    }
                    // East cell.
                    if (!eastEdge && IsCellIndexValid(eastNeighbourIndex) && MazeCells[eastNeighbourIndex].CellState == CellState.Default)
                    {
                        unvisitedNeighbours.Add(MazeCells[eastNeighbourIndex]);
                    }
                    // South cell.
                    if (!southEdge && IsCellIndexValid(southNeighbourIndex) && MazeCells[southNeighbourIndex].CellState == CellState.Default)
                    {
                        unvisitedNeighbours.Add(MazeCells[southNeighbourIndex]);
                    }
                    // West cell.
                    if (!westEdge && IsCellIndexValid(westNeighbourIndex) && MazeCells[westNeighbourIndex].CellState == CellState.Default)
                    {
                        unvisitedNeighbours.Add(MazeCells[westNeighbourIndex]);
                    }

                    if (unvisitedNeighbours.Count > 0)
                    {
                        // The current cell has unvisited neighbours - select a random unvisited neighbour.
                        MazeCell selectedNeighbour = unvisitedNeighbours.ElementAt(_randomNumberGenerator.Next(unvisitedNeighbours.Count));

                        // Remove the wall between the current cell and the selected neighbour.
                        int selectedNeightbourIndex = MazeCells.IndexOf(selectedNeighbour);
                        if (selectedNeightbourIndex == northNeighbourIndex)
                        {
                            currentCell.RemoveWall(Direction.North);
                            selectedNeighbour.RemoveWall(Direction.South);
                        }
                        else if (selectedNeightbourIndex == eastNeighbourIndex)
                        {
                            currentCell.RemoveWall(Direction.East);
                            selectedNeighbour.RemoveWall(Direction.West);
                        }
                        else if (selectedNeightbourIndex == southNeighbourIndex)
                        {
                            currentCell.RemoveWall(Direction.South);
                            selectedNeighbour.RemoveWall(Direction.North);
                        }
                        else if (selectedNeightbourIndex == westNeighbourIndex)
                        {
                            currentCell.RemoveWall(Direction.West);
                            selectedNeighbour.RemoveWall(Direction.East);
                        }

                        // Put the current cell on the stack.
                        _mazeGeneratorStack.Push(currentCell);

                        // Set the selected neighbour as visited.
                        selectedNeighbour.CellState = CellState.Visited;

                        // Repeat the process with the selected neighbour as the new current cell.
                        await GenerateNewMaze(selectedNeighbour);
                    }
                    else
                    {
                        // Set the current cell to empty - it is now part of the maze.
                        currentCell.CellState = CellState.Empty;

                        // The current cell has no unvisited neighbours - pop a cell from the stack.
                        MazeCell previousCell = _mazeGeneratorStack.Pop();
                        previousCell.CellState = CellState.Empty; // Set the popped cell to empty - it is now part of the maze.

                        // Repeat the process with the popped cell as the new current cell.
                        await GenerateNewMaze(previousCell);
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Maze.GenerateNewMaze(MazeCell currentCell): " + ex.ToString());
            }
        }