Exemple #1
0
        /// <summary>
        /// Creates a maze by linking cells using Eller's algorithm
        /// </summary>
        /// <param name="service"></param>
        public override void CreateMaze(MazeGenerationService service)
        {
            //create data structures necessary for algorithm to work
            MazeCell[,] gridcells = service.Cells;
            MazeCell[] cells = gridcells.Cast <MazeCell>().ToArray();

            //assign maze cells their set numbers
            AssignSetNumbers(gridcells, service.DebugMode);

            for (int y = 0; y < gridcells.GetLength(1); y++)
            {
                for (int x = 0; x < gridcells.GetLength(0); x++)
                {
                    //mark cell as visited
                    MazeCell cell = gridcells[x, y];
                    cell.MarkAsVisited();

                    List <MazeCell> neighbours = service.GetNeighboursNotPartOfSet(cell);
                    if (neighbours.Count > 0)
                    {
                        //pick a random neighbour not part of the cells set and create passage between cell and neighbour
                        MazeCell randomNeighbour = neighbours[Random.Range(0, neighbours.Count)];
                        randomNeighbour.CreatePassage(cell);
                        cell.CreatePassage(randomNeighbour);

                        //all the cells belonging to the set the random neighbour belongs to are overtaken by the cell's set
                        MazeCell[] set = cells.Where(c => c.NumberValue == randomNeighbour.NumberValue).ToArray();
                        foreach (MazeCell overtakableCell in set)
                        {
                            overtakableCell.SetNumberValue(cell.NumberValue);
                        }
                    }
                }
            }
        }
Exemple #2
0
        public void Generate(int userLength)
        {
            var maze = new Maze();

            _maze = maze;
            if (OnProgressUpdate != null)
            {
                OnProgressUpdate.Invoke(20); //Updates the loading bar on the MainWindow
            }

            var genMaze = new MazeGenerationService(userLength, userLength, _maze);

            _genMaze = genMaze;

            if (OnProgressUpdate != null)
            {
                OnProgressUpdate.Invoke(70); //Updates the loading bar on the MainWindow
            }

            var play = new MazePlayService(_maze);

            _play = play;

            if (OnProgressUpdate != null)
            {
                OnProgressUpdate.Invoke(10); //Updates the loading bar on the MainWindow
            }

            CreateExitPoint();

            var position = new Mazepoints(0, 0, false, true);

            _position = position;
        }
        /// <summary>
        /// Returns an enumerator that creates a maze by linking cells using the HuntAndKill algorithm
        /// </summary>
        /// <param name="service"></param>
        /// <returns></returns>
        public override IEnumerator CreateMazeRoutine(MazeGenerationService service)
        {
            //create data structures necessary for algorithm to work
            List <MazeCell> visited = new List <MazeCell>();

            //set starting point
            MazeCell walker = service.RootCell;

            walker.MarkAsVisited();
            visited.Add(walker);

            //loop untill all cells have been visited
            long totalCells = service.Cells.LongLength;

            while (visited.Count != totalCells)
            {
                //check if the current walker has unvisited neighbours
                List <MazeCell> unvisitedNeighbours = service.GetUnVisitedNeighbours(walker);
                if (unvisitedNeighbours.Count > 0)
                {
                    //pick a random unvisited neighbour and mark it as visited
                    MazeCell randomUnvisitedNeighbour = unvisitedNeighbours[Random.Range(0, unvisitedNeighbours.Count)];
                    randomUnvisitedNeighbour.MarkAsVisited();
                    visited.Add(randomUnvisitedNeighbour);

                    //create passage between cell and neighbour
                    walker.CreatePassage(randomUnvisitedNeighbour);
                    randomUnvisitedNeighbour.CreatePassage(walker);

                    //the random unvisited neighbour is now the walker
                    walker = randomUnvisitedNeighbour;
                }
                else
                {
                    //scan the grid for a hunted cell that is unvisited but has visited neighbours and mark it as visited
                    MazeCell huntedCell = GetRandomUnVisitedCellWithVisitedNeighbours(service);
                    huntedCell.MarkAsVisited();
                    visited.Add(huntedCell);

                    //fetch one of its visited neighbours and link it with the hunted cell
                    List <MazeCell> visitedNeighbours      = service.GetVisitedNeighbours(huntedCell);
                    MazeCell        randomVisitedNeighbour = visitedNeighbours[Random.Range(0, visitedNeighbours.Count)];
                    huntedCell.CreatePassage(randomVisitedNeighbour);
                    randomVisitedNeighbour.CreatePassage(huntedCell);

                    //the hunted cell is now the walker
                    walker = huntedCell;
                }

                walker.ShowAsStep(true);
                yield return(null);

                walker.ShowAsStep(false);
            }

            CompletedRoutine();
        }
Exemple #4
0
        /// <summary>
        /// Returns an Enumerator that creates a maze by linking cells using the Sidewinder algorithm
        /// </summary>
        /// <param name="service"></param>
        public override IEnumerator CreateMazeRoutine(MazeGenerationService service)
        {
            MazeCell[,] cells = service.Cells;
            int width  = cells.GetLength(0);
            int height = cells.GetLength(1);

            //loop through all the grid, row for row
            for (int y = height - 1; y >= 0; y--)
            {
                //setup an empty set for each row
                List <MazeCell> set = new List <MazeCell>();
                for (int x = 0; x < width; x++)
                {
                    //mark the cell it the row as visited and add it to the set
                    MazeCell cell = cells[x, y];
                    cell.MarkAsVisited();
                    set.Add(cell);

                    //make random decision for cells not on the top
                    if (y + 1 == height || Random.Range(0.0f, 1.0f) > 0.5f)
                    {
                        if (x + 1 < width)
                        {
                            //if the cell east of this cell is not out of width bounds, link the cell with it
                            MazeCell right = cells[x + 1, y];
                            cell.CreatePassage(right);
                            right.CreatePassage(cell);
                        }
                        else if (y + 1 < height)
                        {
                            //if the cell east of this cell is out of width bounds and this is not the top row, link the cell with the cell north of it
                            MazeCell randomCell = set[Random.Range(0, set.Count)];
                            MazeCell top        = cells[randomCell.MazeX, y + 1];

                            randomCell.CreatePassage(top);
                            top.CreatePassage(randomCell);
                        }
                    }
                    else
                    {
                        //if the random decision was not to carve east, carve north from a random cell in the set
                        MazeCell randomCell = set[Random.Range(0, set.Count)];
                        MazeCell top        = cells[randomCell.MazeX, y + 1];

                        randomCell.CreatePassage(top);
                        top.CreatePassage(randomCell);

                        //clear the set after carving north
                        set.Clear();
                    }

                    yield return(null);
                }
            }

            CompletedRoutine();
        }
Exemple #5
0
        /// <summary>
        /// Executes a random walk from given unvisited cell adding visited cells to visited list on finish
        /// </summary>
        /// <param name="unvisitedCell"></param>
        /// <param name="service"></param>
        /// <param name="visited"></param>
        private void RandomWalk(MazeCell unvisitedCell, MazeGenerationService service, List <MazeCell> visited)
        {
            //setup data structures necessary for the random walk to take place
            List <KeyValuePair <MazeCell, Vector2Int> > records = new List <KeyValuePair <MazeCell, Vector2Int> >();
            List <MazeCell> neighbours = service.GetNeighbours(unvisitedCell);

            //pick a random neighbour as the walking position and check whether it is not already visited
            MazeCell walker = neighbours[Random.Range(0, neighbours.Count)];

            if (walker.IsVisited)
            {
                //mark the unvisited cell as visited
                unvisitedCell.MarkAsVisited();
                visited.Add(unvisitedCell);

                //link unvisited cell to the walker and return
                unvisitedCell.CreatePassage(walker);
                walker.CreatePassage(unvisitedCell);
                return;
            }

            //get the direction relative to the walker so we can store it as a record
            Vector2Int direction = unvisitedCell.GetDirectionRelative(walker);

            records.Add(new KeyValuePair <MazeCell, Vector2Int>(unvisitedCell, direction));

            //loop until there are not records left
            while (records.Count != 0)
            {
                //refresh the neighbours list with the walkers neighbours
                neighbours.Clear();
                neighbours.AddRange(service.GetNeighbours(walker));

                //pick a random neighbour, and record the direction from the walker to it
                MazeCell randomNeighbour = neighbours[Random.Range(0, neighbours.Count)];
                direction = walker.GetDirectionRelative(randomNeighbour);

                if (!records.TryUpdate(walker, direction))
                {
                    records.Add(new KeyValuePair <MazeCell, Vector2Int>(walker, direction));
                }

                if (randomNeighbour.IsVisited)
                {
                    //if the random neighbour is visited, carve out a path using the records and clear the records list
                    MarkRecordAsVisitedRecursive(records[0], records, service, visited);
                    records.Clear();
                }
                else
                {
                    //if the random neighbour isn't visited yet, set it as the new walker cell
                    walker = randomNeighbour;
                }
            }
        }
        /// <summary>
        /// Returns an enumerator that creates a maze by linking cells using the recursive backtracking algorithm
        /// </summary>
        /// <param name="service"></param>
        /// <returns></returns>
        public override IEnumerator CreateMazeRoutine(MazeGenerationService service)
        {
            //create data structures necessary for algorithm to work
            Stack <MazeCell> stack   = new Stack <MazeCell>();
            List <MazeCell>  visited = new List <MazeCell>();

            //set starting point
            MazeCell startCell = service.RootCell;

            startCell.MarkAsVisited();
            visited.Add(startCell);
            stack.Push(startCell);

            //loop until all cells have been visited
            long totalCells = service.Cells.LongLength;

            while (visited.Count != totalCells)
            {
                //pick the cell to branch from, from the top of the stack and retreive its neighbours
                MazeCell        newest     = stack.Peek();
                List <MazeCell> neighbours = service.GetUnVisitedNeighbours(newest);

                if (neighbours.Count > 0)
                {
                    //pick a random neighbour from the list
                    MazeCell neighbour = neighbours[Random.Range(0, neighbours.Count)];

                    //set it as visited and add it to the visited list
                    neighbour.MarkAsVisited();
                    visited.Add(neighbour);

                    //create passage between newest and neighbour
                    newest.CreatePassage(neighbour);
                    neighbour.CreatePassage(newest);

                    //push the neighbour to the stack
                    stack.Push(neighbour);
                }
                else
                {
                    //if no unvisited neighbours are available, backtrack by popping the stack
                    stack.Pop();
                }

                newest.ShowAsStep(true);
                yield return(null);

                newest.ShowAsStep(false);
            }

            CompletedRoutine();
        }
        /// <summary>
        /// Returns a random unvisited cell that has visited neighbours
        /// </summary>
        /// <param name="service"></param>
        /// <returns></returns>
        private MazeCell GetRandomUnVisitedCellWithVisitedNeighbours(MazeGenerationService service)
        {
            List <MazeCell> qualifiedCells = new List <MazeCell>();

            foreach (MazeCell cell in service.Cells)
            {
                if (!cell.IsVisited && service.GetVisitedNeighbours(cell).Count > 0)
                {
                    qualifiedCells.Add(cell);
                }
            }

            return(qualifiedCells[Random.Range(0, qualifiedCells.Count)]);
        }
Exemple #8
0
        /// <summary>
        /// Returns an Enumerator that creates a maze by linking cells using the growing tree algorithm its prim version
        /// </summary>
        /// <param name="service"></param>
        public override IEnumerator CreateMazeRoutine(MazeGenerationService service)
        {
            //create data structures necessary for algorithm to work
            List <MazeCell> bag     = new List <MazeCell>();
            List <MazeCell> visited = new List <MazeCell>();

            //set starting point
            MazeCell startPoint = service.RootCell;

            startPoint.MarkAsVisited();
            visited.Add(startPoint);
            bag.Add(startPoint);

            //loop until all cells have been visited
            long totalCells = service.Cells.LongLength;

            while (visited.Count != totalCells)
            {
                //pick a random cell from the bag and check if it has unvisited neighbours
                MazeCell        randomCell          = bag[Random.Range(0, bag.Count)];
                List <MazeCell> unvisitedNeighbours = service.GetUnVisitedNeighbours(randomCell);
                if (unvisitedNeighbours.Count > 0)
                {
                    //pick a random unvisited neighbour and mark it as visited
                    MazeCell randomUnvisitedNeighbour = unvisitedNeighbours[Random.Range(0, unvisitedNeighbours.Count)];
                    randomUnvisitedNeighbour.MarkAsVisited();
                    visited.Add(randomUnvisitedNeighbour);

                    //create passage between cell and neighbour
                    randomCell.CreatePassage(randomUnvisitedNeighbour);
                    randomUnvisitedNeighbour.CreatePassage(randomCell);

                    //add the random unvisited neighbour to the bag
                    bag.Add(randomUnvisitedNeighbour);
                }
                else
                {
                    //if the cell doesn't have any unvisited neighbours, remove it from the bag
                    bag.Remove(randomCell);
                }

                randomCell.ShowAsStep(true);
                yield return(null);

                randomCell.ShowAsStep(false);
            }

            CompletedRoutine();
        }
        /// <summary>
        /// Returns an enumerator that creates a maze by linking cells using prim's algorithm
        /// </summary>
        /// <param name="service"></param>
        /// <returns></returns>
        public override IEnumerator CreateMazeRoutine(MazeGenerationService service)
        {
            //create data structures necessary for algorithm to work
            MazeCell[]      cells    = service.Cells.Cast <MazeCell>().ToArray();
            List <MazeCell> frontier = new List <MazeCell>();

            //set starting point
            MazeCell startCell = service.RootCell;

            startCell.MarkAsVisited();

            //add neighbours of starting cell to frontier
            frontier.AddRange(service.GetNeighbours(startCell));

            while (frontier.Count != 0)
            {
                //pick a random frontier cell, mark it as visited and remove it from the frontier
                MazeCell randomFrontierCell = frontier[Random.Range(0, frontier.Count)];
                randomFrontierCell.MarkAsVisited();
                frontier.Remove(randomFrontierCell);

                //pick a random visited neighbour of it and link it with it
                List <MazeCell> visitedNeighbours = service.GetVisitedNeighbours(randomFrontierCell);
                if (visitedNeighbours.Count > 0)
                {
                    MazeCell randomVisitedNeighbour = visitedNeighbours[Random.Range(0, visitedNeighbours.Count)];
                    randomFrontierCell.CreatePassage(randomVisitedNeighbour);
                    randomVisitedNeighbour.CreatePassage(randomFrontierCell);
                }

                //add unvisited neighbours of it to the frontier if they aren't already in it
                List <MazeCell> unvisitedNeighbours = service.GetUnVisitedNeighbours(randomFrontierCell);
                foreach (MazeCell cell in unvisitedNeighbours)
                {
                    if (!frontier.Contains(cell))
                    {
                        frontier.Add(cell);
                    }
                }

                randomFrontierCell.ShowAsStep(true);
                yield return(null);

                randomFrontierCell.ShowAsStep(false);
            }

            CompletedRoutine();
        }
Exemple #10
0
        /// <summary>
        /// Returns an enumerator that creates a maze by linking cells using Kruskal's algorithm
        /// </summary>
        /// <param name="service"></param>
        /// <returns></returns>
        public override IEnumerator CreateMazeRoutine(MazeGenerationService service)
        {
            //assign each maze cell a number indicating which set it belongs to
            AssignSetNumbers(service.Cells, service.DebugMode);

            //create data structures necessary for algorithm to work
            MazeCell[]      cells = service.Cells.Cast <MazeCell>().ToArray();
            List <MazeCell> bag   = new List <MazeCell>(cells);

            //loop while bag is not not empty
            while (bag.Count != 0)
            {
                //pick a random cell and mark it as visited
                MazeCell randomCell = bag[Random.Range(0, bag.Count)];
                randomCell.MarkAsVisited();

                //fetch the neigbours of this cell that are not part of the same set
                List <MazeCell> neighbours = service.GetNeighboursNotPartOfSet(randomCell);

                if (neighbours.Count > 0)
                {
                    //pick a random neighbour and mark it as visited
                    MazeCell randomNeighbour = neighbours[Random.Range(0, neighbours.Count)];
                    randomNeighbour.MarkAsVisited();

                    //link the random neighbour with the random cell
                    randomNeighbour.CreatePassage(randomCell);
                    randomCell.CreatePassage(randomNeighbour);

                    //all the cells belonging to the set the random neighbour belongs to are overtaken by the random cell's set
                    MazeCell[] set = cells.Where(c => c.NumberValue == randomNeighbour.NumberValue).ToArray();
                    foreach (MazeCell overtakableCell in set)
                    {
                        overtakableCell.SetNumberValue(randomCell.NumberValue);
                    }
                }
                else
                {
                    //if all neighbours of the cel are part of the same set, remove the cell from the bag
                    bag.Remove(randomCell);
                }

                yield return(null);
            }

            CompletedRoutine();
        }
Exemple #11
0
        /// <summary>
        /// Returns an enumerator that creates a maze by linking cells using the adlous broder algorithm
        /// </summary>
        /// <param name="service"></param>
        /// <returns></returns>
        public override IEnumerator CreateMazeRoutine(MazeGenerationService service)
        {
            //create data structures necessary for algorithm to work
            List <MazeCell> visited = new List <MazeCell>();

            //set starting point
            MazeCell startCell = service.RootCell;

            startCell.MarkAsVisited();
            visited.Add(startCell);

            //set current cel as starting cell
            MazeCell currentCell = startCell;

            //loop until all cells have been visited
            long totalCells = service.Cells.LongLength;

            while (visited.Count != totalCells)
            {
                //pick a random neighbour of the current cell
                List <MazeCell> neighbours      = service.GetNeighbours(currentCell);
                MazeCell        randomNeighbour = neighbours[Random.Range(0, neighbours.Count)];

                if (!randomNeighbour.IsVisited)
                {
                    //if the random neighbour hasn't been visited yet, mark it as visited
                    randomNeighbour.MarkAsVisited();
                    visited.Add(randomNeighbour);

                    //create passage between cell and neighbour
                    randomNeighbour.CreatePassage(currentCell);
                    currentCell.CreatePassage(randomNeighbour);
                }

                //set current cell to random neighbour to travel from it
                currentCell = randomNeighbour;

                //show stepping feedback
                currentCell.ShowAsStep(true);
                yield return(null);

                currentCell.ShowAsStep(false);
            }

            CompletedRoutine();
        }
Exemple #12
0
        /// <summary>
        /// Returns a random unvisited cell in the cells grid
        /// </summary>
        /// <param name="service"></param>
        /// <returns></returns>
        private MazeCell GetRandomUnvisitedCell(MazeGenerationService service)
        {
            List <MazeCell> unvisited = new List <MazeCell>();

            for (int x = 0; x < service.Cells.GetLength(0); x++)
            {
                for (int y = 0; y < service.Cells.GetLength(1); y++)
                {
                    MazeCell cell = service.Cells[x, y];
                    if (!cell.IsVisited)
                    {
                        unvisited.Add(cell);
                    }
                }
            }

            return(unvisited[Random.Range(0, unvisited.Count)]);
        }
Exemple #13
0
        /// <summary>
        /// Creates a maze by linking cells using Wilson's algorithm
        /// </summary>
        /// <param name="service"></param>
        public override void CreateMaze(MazeGenerationService service)
        {
            //create data structures necessary for algorithm to work
            List <MazeCell> visited = new List <MazeCell>();

            //set starting point
            MazeCell startPoint = service.RootCell;

            startPoint.MarkAsVisited();
            visited.Add(startPoint);

            //loop until all cells have been visited
            long totalCells = service.Cells.LongLength;

            while (visited.Count != totalCells)
            {
                RandomWalk(GetRandomUnvisitedCell(service), service, visited);
            }
        }
        /// <summary>
        /// Returns the top and right neighbours of given cell using the maze generation service
        /// </summary>
        /// <param name="cell"></param>
        /// <param name="service"></param>
        /// <returns></returns>
        private List <MazeCell> GetTopAndRightNeighbours(MazeCell cell, MazeGenerationService service)
        {
            List <MazeCell> cells = new List <MazeCell>();

            MazeCell top = service.GetTopNeighbour(cell);

            if (top != null)
            {
                cells.Add(top);
            }

            MazeCell right = service.GetRightNeighbour(cell);

            if (right != null)
            {
                cells.Add(right);
            }

            return(cells);
        }
        /// <summary>
        /// Creates a maze by linking cells using the binary tree algorithm
        /// </summary>
        /// <param name="service"></param>
        public override void CreateMaze(MazeGenerationService service)
        {
            foreach (MazeCell cell in service.Cells)
            {
                //mark cell as visited
                cell.MarkAsVisited();

                //retreive the neighbours
                List <MazeCell> neighbours = GetTopAndRightNeighbours(cell, service);
                if (neighbours.Count > 0)
                {
                    //pick a random neighbour
                    MazeCell randomNeighbour = neighbours[Random.Range(0, neighbours.Count)];

                    //create passage between cell and neighbour
                    randomNeighbour.CreatePassage(cell);
                    cell.CreatePassage(randomNeighbour);
                }
            }
        }
Exemple #16
0
 public abstract IEnumerator CreateMazeRoutine(MazeGenerationService service);
Exemple #17
0
 public void Clear() //Ensures that everything is cleared before a new maze is generated
 {
     _maze     = null;
     _genMaze  = null;
     _position = null;
 }
Exemple #18
0
        /// <summary>
        /// Marks the given record as visited and traces all cells back to the visited one using the records list
        /// </summary>
        /// <param name="record"></param>
        /// <param name="records"></param>
        /// <param name="service"></param>
        /// <param name="visited"></param>
        private void MarkRecordAsVisitedRecursive(KeyValuePair <MazeCell, Vector2Int> record, List <KeyValuePair <MazeCell, Vector2Int> > records, MazeGenerationService service, List <MazeCell> visited)
        {
            MazeCell cell = record.Key;

            cell.MarkAsVisited();
            visited.Add(cell);

            Vector2Int direction = record.Value;

            //create passage between cell and next
            MazeCell next = service.Cells[cell.MazeX + direction.x, cell.MazeY + direction.y];

            cell.CreatePassage(next);
            next.CreatePassage(cell);

            if (!next.IsVisited)
            {
                MarkRecordAsVisitedRecursive(records.GetRecord(next), records, service, visited);
            }
        }
Exemple #19
0
 public abstract void CreateMaze(MazeGenerationService service);