コード例 #1
0
ファイル: Maze.cs プロジェクト: prbasha/MazeGenerator
        /// <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());
            }
        }
コード例 #2
0
    private void DoNextGenerationStep(List <MazeCells> activeCells)                     //Continues the Generation
    {
        int       currentIndex = activeCells.Count - 1;
        MazeCells currentCell  = activeCells [currentIndex];

        if (currentCell.IsFullyInitialized)
        {
            activeCells.RemoveAt(currentIndex);
            return;
        }
        MazeDirection direction   = currentCell.RandomUninitializedDirection;
        IntVector2    coordinates = currentCell.coordinates + direction.ToIntVector2();

        if (ContainsCoordinates(coordinates))
        {
            MazeCells neighbor = GetCell(coordinates);
            if (neighbor == null)
            {
                neighbor = CreateCell(coordinates);
                CreatePassage(currentCell, neighbor, direction);
                activeCells.Add(neighbor);
            }
            else
            {
                CreateWall(currentCell, neighbor, direction);
            }
        }
        else
        {
            CreateWall(currentCell, null, direction);
        }
    }
コード例 #3
0
    private void DoNextGenerationStep(List <MazeCells> activeCells)
    {
        int           currentIndex = activeCells.Count - 1;
        MazeCells     currentCell  = activeCells[currentIndex];
        MazeDirection direction    = MazeDirections.RandomValue;
        IntVector2    coordinates  = currentCell.coordinates + direction.ToIntVector2();

        if (ContainsCoordinates(coordinates))
        {
            MazeCells neighbor = GetCell(coordinates);

            if (neighbor == null)
            {
                neighbor = CreateCell(coordinates);

                CreatePassage(currentCell, neighbor, direction);

                activeCells.Add(neighbor);
            }
            else
            {
                CreateWall(currentCell, neighbor, direction);
                activeCells.RemoveAt(currentIndex);
            }
        }
        else
        {
            CreateWall(currentCell, null, direction);
            activeCells.RemoveAt(currentIndex);
        }
    }
コード例 #4
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());
            }
        }
コード例 #5
0
    private void SetNewPosition(Vector2 newPosition)
    {
        // Check if we are not going out the map fist
        if (newPosition.x < 0 || newPosition.y < 0 || newPosition.x > Columns - 1 || newPosition.y > Rows - 1)
        {
            return;
        }

        // Check for the right or left wall
        switch ((int)Position.x - (int)newPosition.x)
        {
        case -1:
            if (MazeCells.ElementAt((int)(Position.x + Position.y * Columns)).Value.GetWallStatus(Cell.CellWalls.RightWall))
            {
                return;
            }

            break;

        case 1:
            if (MazeCells.ElementAt((int)(Position.x + Position.y * Columns)).Value.GetWallStatus(Cell.CellWalls.LeftWall))
            {
                return;
            }

            break;
        }

        // Check for the top or bottom wall
        switch ((int)Position.y - (int)newPosition.y)
        {
        case -1:
            if (MazeCells.ElementAt((int)(Position.x + Position.y * Columns)).Value.GetWallStatus(Cell.CellWalls.TopWall))
            {
                return;
            }

            break;

        case 1:
            if (MazeCells.ElementAt((int)(Position.x + Position.y * Columns)).Value.GetWallStatus(Cell.CellWalls.BottomWall))
            {
                return;
            }

            break;
        }

        Position           = newPosition;
        transform.position = new Vector2(newPosition.x * Width + (Width / 2), newPosition.y * Height + (Height / 2));

        // Show the menu when we reach the end of the maze
        if (Position == new Vector2(Columns - 1, 0))
        {
            MazeManager.ShowMenu();
        }

        nextMove = Time.time + moveInterval;
    }
コード例 #6
0
    private void CreatePassage(MazeCells cell, MazeCells otherCell, MazeDirection direction)
    {
        MazePassage passage = Instantiate(passagePrefab) as MazePassage;

        passage.Initialize(cell, otherCell, direction);
        passage = Instantiate(passagePrefab) as MazePassage;
        passage.Initialize(otherCell, cell, direction.GetOpposite());
    }
コード例 #7
0
 public string GetCellString(GridPoint point)
 {
     if (!MazeCells.ContainsKey(point))
     {
         return(" ");
     }
     return(DonutMazeCell.GetCellString(MazeCells[point]));
 }
コード例 #8
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());
            }
        }
コード例 #9
0
 public void Initialize(MazeCells cell, MazeCells otherCell, MazeDirection direction)
 {
     this.cell      = cell;
     this.otherCell = otherCell;
     this.direction = direction;
     cell.SetEdge(direction, this);
     transform.parent        = cell.transform;
     transform.localPosition = Vector3.zero;
     transform.localRotation = direction.ToRotation();
 }
コード例 #10
0
        private void ConstructPortals()
        {
            PortalCells = new Dictionary <GridPoint, string>();
            Portals     = new Dictionary <string, IList <GridPoint> >();
            var emptyCells = MazeCells
                             .Where(kvp => DonutMazeCellType.Empty.Equals(kvp.Value.Type));

            foreach (var emptyCell in emptyCells)
            {
                var point = emptyCell.Key;
                var movementDirections = new List <MovementDirection>()
                {
                    MovementDirection.Down,
                    MovementDirection.Left,
                    MovementDirection.Right,
                    MovementDirection.Up
                };
                foreach (var direction in movementDirections)
                {
                    // Assumption: One point can only be associated with at
                    // most one portal.
                    var neighbor1 = point.Move(direction, 1);
                    if (!MazeCells.ContainsKey(neighbor1) ||
                        !DonutMazeCellType.Portal.Equals(MazeCells[neighbor1].Type))
                    {
                        continue;
                    }
                    var neighbor2 = point.Move(direction, 2);
                    if (!MazeCells.ContainsKey(neighbor2) ||
                        !DonutMazeCellType.Portal.Equals(MazeCells[neighbor2].Type))
                    {
                        throw new Exception("Only one neighboring portal cell found");
                    }
                    var portalId = string.Empty;
                    if (MovementDirection.Right.Equals(direction) ||
                        MovementDirection.Up.Equals(direction))
                    {
                        portalId = MazeCells[neighbor1].PortalLetter + MazeCells[neighbor2].PortalLetter;
                    }
                    else
                    {
                        portalId = MazeCells[neighbor2].PortalLetter + MazeCells[neighbor1].PortalLetter;
                    }

                    PortalCells.Add(point, portalId);
                    if (!Portals.ContainsKey(portalId))
                    {
                        Portals.Add(portalId, new List <GridPoint>());
                    }
                    Portals[portalId].Add(point);
                }
            }
            EntrancePoint = new GridPoint3D(Portals[EntrancePortalId][0], 0);
            ExitPoint     = new GridPoint3D(Portals[ExitPortalId][0], 0);
        }
コード例 #11
0
    private void CreateWall(MazeCells cell, MazeCells otherCell, MazeDirection direction)
    {
        MazeWall wall = Instantiate(wallPrefab) as MazeWall;

        wall.Initialize(cell, otherCell, direction);
        if (otherCell != null)
        {
            wall = Instantiate(wallPrefab) as MazeWall;
            wall.Initialize(otherCell, cell, direction.GetOpposite());
        }
    }
コード例 #12
0
    private MazeCells CreateCell(IntVector2 coordinates)
    {
        MazeCells newCell = Instantiate(cellPrefab) as MazeCells;

        cells[coordinates.x, coordinates.z] = newCell;
        newCell.coordinates             = coordinates;
        newCell.name                    = "Maze Cell " + coordinates.x + ", " + coordinates.z;
        newCell.transform.parent        = transform;
        newCell.transform.localPosition =
            new Vector3(coordinates.x - size.x * 0.5f + 0.5f, 0f, coordinates.z - size.z * 0.5f + 0.5f);
        return(newCell);
    }
コード例 #13
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());
            }
        }
コード例 #14
0
    public void InitVars()
    {
        // Remove all the cells we currently have
        if (previousCells.Count > 0)
        {
            foreach (GameObject cell in previousCells)
            {
                Destroy(cell);
            }
        }

        // Recalculate the cell width and height
        CellWidth  = (float)Screen.width / (float)MazeInput.Instance.MazeColumns;
        CellHeight = (float)Screen.height / (float)MazeInput.Instance.MazeRows;

        // Empty the cells list for repopulation
        previousCells.Clear();
        MazeCells.Clear();
    }
コード例 #15
0
ファイル: Maze.cs プロジェクト: prbasha/MazeGenerator
 /// <summary>
 /// The ChooseRandomCell method is called to choose a random cell in the maze.
 /// </summary>
 /// <returns></returns>
 private MazeCell ChooseRandomCell()
 {
     try
     {
         // Select a random cell to start.
         int cellIndex = _randomNumberGenerator.Next(Constants.MazeHeight * Constants.MazeWidth);
         if (IsCellIndexValid(cellIndex))
         {
             return(MazeCells.ElementAt(cellIndex));
         }
         else
         {
             throw new Exception("Unable to choose a randmom cell.");
         }
     }
     catch (Exception ex)
     {
         throw new Exception("Maze.ChooseRandomCell(): " + ex.ToString());
     }
 }
コード例 #16
0
ファイル: Cell.cs プロジェクト: Smehi/Perfect-Maze-Gen
    public GameObject GetRandomAvailableNeighbour()
    {
        List <GameObject> neighbours = new List <GameObject>();

        // Check if the position is available first and then add it
        Cell top    = GetIndex(Position.x, Position.y + 1) != -1 ? MazeCells.ElementAt(GetIndex(Position.x, Position.y + 1)).Value : null;
        Cell right  = GetIndex(Position.x + 1, Position.y) != -1 ? MazeCells.ElementAt(GetIndex(Position.x + 1, Position.y)).Value : null;
        Cell bottom = GetIndex(Position.x, Position.y - 1) != -1 ? MazeCells.ElementAt(GetIndex(Position.x, Position.y - 1)).Value : null;
        Cell left   = GetIndex(Position.x - 1, Position.y) != -1 ? MazeCells.ElementAt(GetIndex(Position.x - 1, Position.y)).Value : null;

        // If the neighbours are available and not visited add them to our neighbours list
        if (top && !top.IsVisited)
        {
            neighbours.Add(top.gameObject);
        }

        if (right && !right.IsVisited)
        {
            neighbours.Add(right.gameObject);
        }

        if (bottom && !bottom.IsVisited)
        {
            neighbours.Add(bottom.gameObject);
        }

        if (left && !left.IsVisited)
        {
            neighbours.Add(left.gameObject);
        }

        // Choose one at random if we have neighbours
        if (neighbours.Count > 0)
        {
            return(neighbours[Random.Range(0, neighbours.Count)]);
        }
        else
        {
            return(null);
        }
    }
コード例 #17
0
        /// <summary>
        /// The ChooseRandomCell method is called to choose a random cell in the maze.
        /// This random cell can not be on the edge of the maze, as the maze edges are all walls.
        /// </summary>
        /// <returns></returns>
        private MazeCell ChooseRandomCell()
        {
            try
            {
                // X and Y indexes must not be on the edges - a offset of 2 is used to ensure this.
                int cellIndexX = _randomNumberGenerator.Next(2, MazeWidthHeightCells - 2);
                int cellIndexY = _randomNumberGenerator.Next(2, MazeWidthHeightCells - 2);

                if (IsCellIndexValid(cellIndexX * cellIndexY))
                {
                    return(MazeCells.ElementAt(cellIndexX * cellIndexY));
                }
                else
                {
                    throw new Exception("Unable to choose a random cell.");
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Maze.ChooseRandomCell(): " + ex.ToString());
            }
        }
コード例 #18
0
    public void GenerateGrid()
    {
        // Nested for-loop to fill the screen with cells
        for (int y = 0; y < MazeInput.Instance.MazeRows; y++)
        {
            for (int x = 0; x < MazeInput.Instance.MazeColumns; x++)
            {
                // Make the cell and set the properties
                GameObject cell = Instantiate(MazeInput.Instance.CellPrefab);

                // We set the parent first because we want to set the position relative to the canvas
                cell.transform.SetParent(MazeInput.Instance.MazeCanvas.transform);

                // Set the position with a small offset because the pivot point of the cell is in the center
                cell.transform.position   = new Vector2(x * CellWidth + (CellWidth / 2), y * CellHeight + (CellHeight / 2));
                cell.transform.localScale = new Vector2(CellWidth, CellHeight);
                cell.name = "Cell: " + (x + (y * MazeInput.Instance.MazeColumns));

                // Set the index of the cell
                Cell cellScript = cell.GetComponent <Cell>();
                cellScript.Position    = new Vector2(x, y);
                cellScript.MazeRows    = MazeInput.Instance.MazeRows;
                cellScript.MazeColumns = MazeInput.Instance.MazeColumns;

                // Set the cell colors
                cellScript.BackgroundColor = MazeInput.Instance.CellBackgroundColor;
                cellScript.WallColor       = MazeInput.Instance.CellWallColor;
                cellScript.HighlightColor  = MazeInput.Instance.CellHighlightColor;
                cellScript.VisitedColor    = MazeInput.Instance.CellVisitedColor;

                previousCells.Add(cell);
                MazeCells.Add(cell, cellScript);
            }
        }

        // We do this at the end of generating the maze just so we have a start and end from the top left cell and bottom right cell
        MazeCells.ElementAt((MazeInput.Instance.MazeRows - 1) * MazeInput.Instance.MazeColumns).Value.RemoveWall(Cell.CellWalls.LeftWall);
        MazeCells.ElementAt(MazeInput.Instance.MazeColumns - 1).Value.RemoveWall(Cell.CellWalls.RightWall);
    }
コード例 #19
0
        private void CalculateMazeBoundaries()
        {
            OuterWallLeft = MazeCells
                            .Where(kvp => !DonutMazeCellType.Portal.Equals(kvp.Value.Type))
                            .Min(kvp => kvp.Key.X);
            OuterWallRight = MazeCells
                             .Where(kvp => !DonutMazeCellType.Portal.Equals(kvp.Value.Type))
                             .Max(kvp => kvp.Key.X);
            OuterWallTop = MazeCells
                           .Where(kvp => !DonutMazeCellType.Portal.Equals(kvp.Value.Type))
                           .Min(kvp => kvp.Key.Y);
            OuterWallBottom = MazeCells
                              .Where(kvp => !DonutMazeCellType.Portal.Equals(kvp.Value.Type))
                              .Max(kvp => kvp.Key.Y);
            int midX = (OuterWallRight - OuterWallLeft) / 2;
            int midY = (OuterWallBottom - OuterWallTop) / 2;

            InnerWallLeft = MazeCells
                            .Where(kvp => !DonutMazeCellType.Portal.Equals(kvp.Value.Type) &&
                                   kvp.Key.X <= midX &&
                                   kvp.Key.Y == midY)
                            .Max(kvp => kvp.Key.X);
            InnerWallRight = MazeCells
                             .Where(kvp => !DonutMazeCellType.Portal.Equals(kvp.Value.Type) &&
                                    kvp.Key.X >= midX &&
                                    kvp.Key.Y == midY)
                             .Min(kvp => kvp.Key.X);
            InnerWallTop = MazeCells
                           .Where(kvp => !DonutMazeCellType.Portal.Equals(kvp.Value.Type) &&
                                  kvp.Key.Y <= midY &&
                                  kvp.Key.X == midX)
                           .Max(kvp => kvp.Key.Y);
            InnerWallBottom = MazeCells
                              .Where(kvp => !DonutMazeCellType.Portal.Equals(kvp.Value.Type) &&
                                     kvp.Key.Y >= midY &&
                                     kvp.Key.X == midX)
                              .Min(kvp => kvp.Key.Y);
        }
コード例 #20
0
ファイル: Maze.cs プロジェクト: erjicles/AdventOfCode2019
        public bool GetCanEnterCell(
            GridPoint point,
            SortedDictionary <string, string> keysCollected,
            bool ignoreDoors = false)
        {
            if (!MazeCells.ContainsKey(point))
            {
                return(false);
            }
            var cell = MazeCells[point];

            if (MazeCellType.Wall.Equals(cell.Type))
            {
                return(false);
            }
            if (!ignoreDoors &&
                CellsWithDoors.ContainsKey(point) &&
                !keysCollected.ContainsKey(CellsWithDoors[point].ToLower()))
            {
                return(false);
            }
            return(true);
        }
コード例 #21
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());
            }
        }
コード例 #22
0
ファイル: Maze.cs プロジェクト: erjicles/AdventOfCode2019
        public IList <GridPoint> GetPointNeighbors(
            GridPoint point,
            SortedDictionary <string, string> keysCollected,
            GridPoint specificNeighborToAllow = null,
            bool ignoreDoors = false)
        {
            var neighbors  = new List <GridPoint>();
            var candidates = new List <GridPoint>()
            {
                point.MoveLeft(1),
                point.MoveRight(1),
                point.MoveUp(1),
                point.MoveDown(1)
            };

            foreach (var candidate in candidates)
            {
                if (!MazeCells.ContainsKey(candidate))
                {
                    continue;
                }
                var  candidateCell        = MazeCells[candidate];
                bool checkIfCanCenterCell = !(
                    specificNeighborToAllow != null &&
                    specificNeighborToAllow.Equals(candidate));
                if (checkIfCanCenterCell)
                {
                    if (!GetCanEnterCell(candidate, keysCollected, ignoreDoors))
                    {
                        continue;
                    }
                }
                neighbors.Add(candidate);
            }
            return(neighbors);
        }
コード例 #23
0
        public IList <GridPoint3D> GetEmptyNeighbors(GridPoint3D currentPosition)
        {
            var result             = new List <GridPoint3D>();
            var movementDirections = new List <MovementDirection>()
            {
                MovementDirection.Down,
                MovementDirection.Left,
                MovementDirection.Right,
                MovementDirection.Up
            };

            foreach (var movementDirection in movementDirections)
            {
                var neighborPoint = currentPosition.Move(movementDirection, 1);
                if (!MazeCells.ContainsKey(neighborPoint.XYPoint))
                {
                    continue;
                }
                var type = MazeCells[neighborPoint.XYPoint].Type;
                if (DonutMazeCellType.Wall.Equals(type))
                {
                    continue;
                }
                if (DonutMazeCellType.Empty.Equals(type))
                {
                    result.Add(neighborPoint);
                }
                else if (DonutMazeCellType.Portal.Equals(type))
                {
                    // Assumption: One point can be associated with at most
                    // one portal
                    var portalId = PortalCells[currentPosition.XYPoint];
                    if (EntrancePortalId.Equals(portalId) ||
                        ExitPortalId.Equals(portalId))
                    {
                        continue;
                    }

                    bool isOnOuterEdge = GetIsOnOuterWall(currentPosition);
                    // If this is a recursive maze, then outer portals only
                    // work for z > 1
                    if (IsRecursive &&
                        isOnOuterEdge &&
                        currentPosition.Z == 0)
                    {
                        continue;
                    }

                    var connectedPoint = Portals[portalId]
                                         .Where(p => !p
                                                .Equals(currentPosition.XYPoint))
                                         .FirstOrDefault();
                    if (connectedPoint == null)
                    {
                        throw new Exception("Portal found with no connected point");
                    }

                    // Handle recursive maze - if this is an inner portal, then
                    // we are going in a level, so increment z
                    // If this is an outer portal, then we are going out a
                    // level, so decrease z
                    int connectedPointZ = currentPosition.Z;
                    if (IsRecursive)
                    {
                        if (isOnOuterEdge)
                        {
                            connectedPointZ--;
                        }
                        else if (GetIsOnInnerWall(currentPosition))
                        {
                            connectedPointZ++;
                        }
                    }
                    // The connected point is stored in the maze at z=0, so
                    // move it to the appropriate z index
                    result.Add(new GridPoint3D(connectedPoint, connectedPointZ));
                }
                else
                {
                    throw new Exception($"Invalid cell type {type}");
                }
            }
            return(result);
        }
コード例 #24
0
 public void DrawMaze()
 {
     GridHelper.DrawGrid2D(
         gridPoints: MazeCells.Select(kvp => kvp.Key).ToList(),
         GetPointString: GetCellString);
 }
コード例 #25
0
 public IList <Tuple <string, ConsoleColor> > GetMazeRenderingData()
 {
     return(GridHelper.GetGridRenderingData(
                gridPoints: MazeCells.Select(kvp => kvp.Key).ToList(),
                GetPointString: GetCellString));
 }
コード例 #26
0
ファイル: Maze.cs プロジェクト: prbasha/MazeGenerator
        /// <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());
            }
        }
コード例 #27
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());
            }
        }