public AbstractMaze(int rows, int columns)
 {
     Rows       = rows;
     Columns    = columns;
     m_Maze     = new AbstractMazeCell <T> [Rows, Columns];
     BuildStack = new Stack <AbstractMazeCell <T> >();
     Random     = new Random();
 }
        public AbstractMazeCell <T> GetExitFromOriginAndDepth(AbstractMazeCell <T> origin, int moves)
        {
            var solutionPath = GetPathFromOriginToExit(origin, null, moves);

            if (solutionPath != null)
            {
                return(solutionPath[solutionPath.Count - 1]);
            }
            return(null);
        }
 public void ResetMaze()
 {
     BuildOrigin = null;
     for (int rowIndex = 0; rowIndex < Rows; rowIndex++)
     {
         for (int columnIndex = 0; columnIndex < Columns; columnIndex++)
         {
             m_Maze[rowIndex, columnIndex] = new AbstractMazeCell <T>(rowIndex, columnIndex);
         }
     }
 }
        public List <AbstractMazeCell <T> > GetPathFromOriginToExit(AbstractMazeCell <T> origin, AbstractMazeCell <T> exit, int killDepth)
        {
            var solutionPath              = new List <AbstractMazeCell <T> >();
            var ProcessedCellsList        = new List <AbstractMazeCell <T> >();
            var ProcessedCellsOriginsList = new List <AbstractMazeCell <T> >();
            var CellQueue = new Queue <AbstractMazeCell <T> >();

            // breadth-frist algorithm
            var currentCell = origin;

            ProcessedCellsOriginsList.Add(currentCell);
            while (currentCell != null)
            {
                solutionPath.Clear();
                currentCell.Status = AbstractMazeCellStatuses.Processed;
                if (currentCell.North_Neighbor != null && currentCell.North_Neighbor.Status.Equals(AbstractMazeCellStatuses.Ready))
                {
                    CellQueue.Enqueue(currentCell.North_Neighbor);
                    ProcessedCellsOriginsList.Add(currentCell);
                    currentCell.North_Neighbor.Status = AbstractMazeCellStatuses.Queued;
                }
                if (currentCell.West_Neighbor != null && currentCell.West_Neighbor.Status.Equals(AbstractMazeCellStatuses.Ready))
                {
                    CellQueue.Enqueue(currentCell.West_Neighbor);
                    ProcessedCellsOriginsList.Add(currentCell);
                    currentCell.West_Neighbor.Status = AbstractMazeCellStatuses.Queued;
                }
                if (currentCell.East_Neighbor != null && currentCell.East_Neighbor.Status.Equals(AbstractMazeCellStatuses.Ready))
                {
                    CellQueue.Enqueue(currentCell.East_Neighbor);
                    ProcessedCellsOriginsList.Add(currentCell);
                    currentCell.East_Neighbor.Status = AbstractMazeCellStatuses.Queued;
                }
                if (currentCell.South_Neighbor != null && currentCell.South_Neighbor.Status.Equals(AbstractMazeCellStatuses.Ready))
                {
                    CellQueue.Enqueue(currentCell.South_Neighbor);
                    ProcessedCellsOriginsList.Add(currentCell);
                    currentCell.South_Neighbor.Status = AbstractMazeCellStatuses.Queued;
                }
                ProcessedCellsList.Add(currentCell);

                // if the solution is found, force finish
                if (exit != null && currentCell.Equals(exit))
                {
                    CellQueue.Clear();
                }

                // process the solution, check its length for kill depth
                var parentCell      = currentCell;
                int parentCellIndex = -1;
                while (!parentCell.Equals(origin))
                {
                    solutionPath.Insert(0, parentCell);
                    parentCellIndex = ProcessedCellsList.IndexOf(parentCell);
                    parentCell      = ProcessedCellsOriginsList[parentCellIndex];
                }

                // check for kill depth, force finish if reached
                if (solutionPath.Count == killDepth)
                {
                    CellQueue.Clear();
                }

                // add the origin to the beginning
                solutionPath.Insert(0, origin);

                // finally, if there is another cell to process from the queue, do so
                if (CellQueue.Count > 0)
                {
                    currentCell = CellQueue.Dequeue();
                }
                else
                {
                    currentCell = null;
                }
            }
            // reset maze for next solution
            UnprocessCells();
            return(solutionPath);
        }
        // Currently only uses the recursive backtracking algorithm
        public void BuildFromOrigin(int rowOrigin, int columnOrigin)
        {
            ResetMaze();
            BuildOrigin = m_Maze[rowOrigin, columnOrigin];

            // recursive backtracking
            var currentCell = BuildOrigin;

            currentCell.Status = AbstractMazeCellStatuses.Ready;
            while (currentCell != null)
            {
                // neighbor options
                var neighborOptions = new List <AbstractMazeCell <T> >();

                // push north neighbor
                if (currentCell.Row - 1 > -1)
                {
                    if (!m_Maze[currentCell.Row - 1, currentCell.Column].Status.Equals(AbstractMazeCellStatuses.Ready))
                    {
                        neighborOptions.Add(m_Maze[currentCell.Row - 1, currentCell.Column]);
                    }
                }
                // push west neighbor
                if (currentCell.Column - 1 > -1)
                {
                    if (!m_Maze[currentCell.Row, currentCell.Column - 1].Status.Equals(AbstractMazeCellStatuses.Ready))
                    {
                        neighborOptions.Add(m_Maze[currentCell.Row, currentCell.Column - 1]);
                    }
                }
                // push east neighbor
                if (currentCell.Column + 1 < Columns)
                {
                    if (!m_Maze[currentCell.Row, currentCell.Column + 1].Status.Equals(AbstractMazeCellStatuses.Ready))
                    {
                        neighborOptions.Add(m_Maze[currentCell.Row, currentCell.Column + 1]);
                    }
                }
                // push south neighbor
                if (currentCell.Row + 1 < Rows)
                {
                    if (!m_Maze[currentCell.Row + 1, currentCell.Column].Status.Equals(AbstractMazeCellStatuses.Ready))
                    {
                        neighborOptions.Add(m_Maze[currentCell.Row + 1, currentCell.Column]);
                    }
                }

                // if there are options, choose one and push currentCell to stack
                if (neighborOptions.Count > 0)
                {
                    DeadEnd = false;
                    // choose a neighbor at random
                    var index      = Random.Next(0, neighborOptions.Count);
                    var chosenCell = neighborOptions[index];

                    // push currentCell onto stack
                    BuildStack.Push(currentCell);

                    // whichever neighbor was chosen needs to have a path declared to and from currentCell
                    if (chosenCell.Row == currentCell.Row)
                    {
                        if (chosenCell.Column == currentCell.Column - 1) // west neighbor
                        {
                            currentCell.West_Neighbor = chosenCell;
                            chosenCell.East_Neighbor  = currentCell;
                        }
                        else // east neighbor => chosenCell.Column == currentCell.Column + 1
                        {
                            currentCell.East_Neighbor = chosenCell;
                            chosenCell.West_Neighbor  = currentCell;
                        }
                    }
                    else
                    {
                        if (chosenCell.Row == currentCell.Row - 1) // north neighbor
                        {
                            currentCell.North_Neighbor = chosenCell;
                            chosenCell.South_Neighbor  = currentCell;
                        }
                        else // south neighbor => chosenCell.Row == currentCell.Row + 1
                        {
                            currentCell.South_Neighbor = chosenCell;
                            chosenCell.North_Neighbor  = currentCell;
                        }
                    }

                    // make chosen into current after processing
                    chosenCell.Status = AbstractMazeCellStatuses.Ready;
                    currentCell       = chosenCell;
                }
                // there are no neighbor options, pop a cell off the stack and make it current
                else
                {
                    OnFinalProcessingCell?.Invoke(currentCell);
                    if (!DeadEnd)
                    {
                        DeadEnd = true;
                        OnDeadEndCreation?.Invoke(currentCell);
                    }
                    if (BuildStack.Count > 0)
                    {
                        currentCell = BuildStack.Pop();
                    }
                    else
                    {
                        currentCell = null;
                    }
                }
            }
            // the origin is always a dead end, too
            OnDeadEndCreation?.Invoke(BuildOrigin);

            // the maze is generated
            OnMazeGenerated?.Invoke(m_Maze);
        }
 public static MazeWallConfigCodes GetWallConfig(AbstractMazeCell <T> cell)
 {
     if (cell.North_Neighbor != null)
     {
         if (cell.West_Neighbor != null)
         {
             if (cell.East_Neighbor != null)
             {
                 if (cell.South_Neighbor != null)
                 {
                     return(MazeWallConfigCodes.None);
                 }
                 else // south is null
                 {
                     return(MazeWallConfigCodes.South_Only);
                 }
             }
             else // east is null
             {
                 if (cell.South_Neighbor != null)
                 {
                     return(MazeWallConfigCodes.East_Only);
                 }
                 else // south is null
                 {
                     return(MazeWallConfigCodes.East_South);
                 }
             }
         }
         else // west is null
         {
             if (cell.East_Neighbor != null)
             {
                 if (cell.South_Neighbor != null)
                 {
                     return(MazeWallConfigCodes.West_Only);
                 }
                 else // south is null
                 {
                     return(MazeWallConfigCodes.West_South);
                 }
             }
             else // east is null
             {
                 if (cell.South_Neighbor != null)
                 {
                     return(MazeWallConfigCodes.West_East);
                 }
                 else // south is null
                 {
                     return(MazeWallConfigCodes.West_East_South);
                 }
             }
         }
     }
     else // north is null
     {
         if (cell.West_Neighbor != null)
         {
             if (cell.East_Neighbor != null)
             {
                 if (cell.South_Neighbor != null)
                 {
                     return(MazeWallConfigCodes.North_Only);
                 }
                 else // south is null
                 {
                     return(MazeWallConfigCodes.North_South);
                 }
             }
             else // east is null
             {
                 if (cell.South_Neighbor != null)
                 {
                     return(MazeWallConfigCodes.North_East);
                 }
                 else // south is null
                 {
                     return(MazeWallConfigCodes.North_East_South);
                 }
             }
         }
         else // west is null
         {
             if (cell.East_Neighbor != null)
             {
                 if (cell.South_Neighbor != null)
                 {
                     return(MazeWallConfigCodes.North_West);
                 }
                 else // south is null
                 {
                     return(MazeWallConfigCodes.North_West_South);
                 }
             }
             else // east is null
             {
                 if (cell.South_Neighbor != null)
                 {
                     return(MazeWallConfigCodes.North_West_East);
                 }
                 else // not possible without adding different maze genrating algorithms to AbstractMazeGenerator.cs
                 {
                     return(MazeWallConfigCodes.All);
                 }
             }
         }
     }
 }