public override void CreateMaze() { MazeCell currentCell = GetRandomCell(); while (currentCell) { List <MazeCell> unvisitedNeighbours = currentCell.Neighbors.Where(c => c.GetLinks().Count == 0).ToList(); if (unvisitedNeighbours.Count > 0) { MazeCell neighbour = unvisitedNeighbours[Random.Range(0, unvisitedNeighbours.Count)]; currentCell.CreatePassage(neighbour); currentCell = neighbour; } else // Hunt { currentCell = null; foreach (var cell in cells) { List <MazeCell> visitedNeighbours = cell.Neighbors.Where(c => c.GetLinks().Count > 0).ToList(); if (cell.GetLinks().Count == 0 && visitedNeighbours.Count > 0) { currentCell = cell; MazeCell neighbour = visitedNeighbours[Random.Range(0, visitedNeighbours.Count)]; currentCell.CreatePassage(neighbour); break; } } } } }
/// <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); } } } } }
public override void CreateMaze() { for (int r = 0; r < mazeRows; r++) { List <MazeCell> run = new List <MazeCell>(); for (int c = 0; c < mazeColumns; c++) { MazeCell currentCell = cells[c, r]; run.Add(currentCell); bool isAtEasternBoundary = (currentCell.East == null); bool isAtNorthernBoundary = (currentCell.North == null); bool shouldCloseOut = isAtEasternBoundary || (!isAtNorthernBoundary && Random.Range(0, 2) == 0); if (shouldCloseOut) { MazeCell member = run[Random.Range(0, run.Count)]; if (member.North != null) { member.CreatePassage(member.North); } run.Clear(); } else { currentCell.CreatePassage(currentCell.East); } } } }
internal void CreatePassage(MazeCell neighbour, bool bidirectional = true) { links[neighbour] = true; if (bidirectional) { neighbour.CreatePassage(this, false); } }
/// <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(); }
/// <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(); }
/// <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 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(); }
/// <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(); }
/// <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(); }
/// <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); } } }
/// <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); } }
public override void CreateMaze() { List <MazeCell> activeCells = new List <MazeCell>(); activeCells.Add(GetRandomCell()); while (activeCells.Count > 0) { MazeCell currentCell = activeCells[activeCells.Count - 1]; List <MazeCell> availableNeighbours = currentCell.Neighbors.Where(c => c.GetLinks().Count == 0).ToList(); if (availableNeighbours.Count > 0) { MazeCell neighbour = availableNeighbours[Random.Range(0, availableNeighbours.Count)]; currentCell.CreatePassage(neighbour); activeCells.Add(neighbour); } else { activeCells.Remove(currentCell); } } }