/// <summary> /// Returns an enumerator that solves the maze by creating a solution path using the WallFollower Algorithm /// </summary> /// <param name="service"></param> public override IEnumerator SolveMazeRoutine(MazeSolvingService service) { //set starting point MazeCell walker = service.EntranceCell; walker.MarkAsPartOfSolution(); //store direction for manipulation Vector2Int direction = Vector2Int.left; //loop until exit has been reached by the walker MazeCell exitCell = service.ExitCell; while (walker != exitCell) { //try first walking left and then walking forward. Rotate right if both fail MazeCell nextCellInPath = null; if (service.GetNextCellInPathRelative(walker, GetValueRotatedLeft(direction), ref nextCellInPath)) { //if we can walk left, first rotate left Rotate(ANGLE_LEFT, ref direction); //make the next cell in the path and the passage towards it part of the solution nextCellInPath.MarkAsPartOfSolution(); nextCellInPath.MarkWallAsPartOfSolution(walker); walker.MarkWallAsPartOfSolution(nextCellInPath); } else if (service.GetNextCellInPathRelative(walker, direction, ref nextCellInPath)) { //make the next cell in the path and the passage towards it part of the solution nextCellInPath.MarkAsPartOfSolution(); nextCellInPath.MarkWallAsPartOfSolution(walker); walker.MarkWallAsPartOfSolution(nextCellInPath); } else { //rotate right to look for a new way to walk left or forward Rotate(ANGLE_RIGHT, ref direction); } if (nextCellInPath != null) { //if the next cell in the path was found, we can walk on from it walker = nextCellInPath; if (service.DebugMode) { walker.SetDirectionArrow(direction); walker.ShowDirectionArrow(true); } } yield return(null); } CompletedRoutine(); }
/// <summary> /// Returns an enumerator that solves the maze by creating a solution path using the Recursive Backtracking Algorithm /// </summary> /// <param name="service"></param> public override IEnumerator SolveMazeRoutine(MazeSolvingService service) { //create datastructues necessary for algorithm to work Stack <MazeCell> stack = new Stack <MazeCell>(); //set starting point and store exit for loop condition MazeCell exitCell = service.ExitCell; MazeCell entrance = service.EntranceCell; entrance.MarkAsPartOfSolution(); stack.Push(entrance); //loop until the next cell in path is the exit MazeCell nextCellInPath = null; while (nextCellInPath != exitCell) { //look at the cell at the top of the stack and get the next cells in the path relative to it MazeCell cell = stack.Peek(); List <MazeCell> cellsNextInPath = service.GetNextCellsInPath(cell); //check if the path is a dead end or not if (cellsNextInPath.Count > 0) { //fetch a random cell that is next in the path and mark it as part of the solution nextCellInPath = cellsNextInPath[Random.Range(0, cellsNextInPath.Count)]; nextCellInPath.MarkAsPartOfSolution(); //mark the walls as part of the solution aswell cell.MarkWallAsPartOfSolution(nextCellInPath); nextCellInPath.MarkWallAsPartOfSolution(cell); //push the next cell to the stack stack.Push(nextCellInPath); } else { //mark the dead end and its broken walls as checked, so not part of the solution anymore cell.MarkAsChecked(); cell.MarkBrokenWallsAsChecked(); //pop the stack to backtrack stack.Pop(); } yield return(null); } CompletedRoutine(); }
/// <summary> /// Returns an enumerator that solves the maze by creating a solution path using the DeadEndFilling Algorithm /// </summary> /// <param name="service"></param> public override IEnumerator SolveMazeRoutine(MazeSolvingService service) { //fill dead ends of the maze until junktions are found IEnumerable <MazeCell> deadEnds = service.Cells.Cast <MazeCell>().Where(cell => cell.IsDeadEnd); foreach (MazeCell deadEnd in deadEnds) { yield return(CheckUntilJunctionRoutine(deadEnd, service)); } //start walking from the entrance MazeCell walker = service.EntranceCell; walker.MarkAsPartOfSolution(); yield return(null); //loop until the walker is at the exit MazeCell exitCell = service.ExitCell; while (walker != exitCell) { //get the next cell that is on current path List <MazeCell> nextCellsInPath = service.GetNextCellsInPath(walker); if (nextCellsInPath.Count == 1) { //make the cell part of the path solution MazeCell nextCellInPath = nextCellsInPath[0]; nextCellInPath.MarkAsPartOfSolution(); //mark its walls as part of the solution aswell walker.MarkWallAsPartOfSolution(nextCellInPath); nextCellInPath.MarkWallAsPartOfSolution(walker); //the next cell in the path is now the walker walker = nextCellInPath; } else { throw new System.InvalidOperationException($"The solution path could not be created from {walker.name} with {nextCellsInPath.Count} next cells in path :: this is unintended behaviour!"); } yield return(null); } CompletedRoutine(); }
/// <summary> /// Returns an enumerator that marks the maze as checked from given walker cell until a junction is met /// </summary> /// <param name="walker"></param> /// <param name="service"></param> /// <returns></returns> private IEnumerator CheckUntilJunctionRoutine(MazeCell walker, MazeSolvingService service) { walker.MarkAsChecked(); yield return(null); //loop until a junction is found and is borken out of the loop while (true) { //get the next cell in the current path List <MazeCell> cellsNextInPath = service.GetNextCellsInPath(walker); if (cellsNextInPath.Count == 1) { //save it is a junction MazeCell nextCellInPath = cellsNextInPath[0]; bool isJunction = nextCellInPath.IsJunction; //mark the walls as checked walker.MarkWallAsChecked(nextCellInPath); nextCellInPath.MarkWallAsChecked(walker); if (isJunction) { //if the cell was a junction, break out of the loop break; } else { //if the cell wasn't a junction, mark the cell as checked and continue from it nextCellInPath.MarkAsChecked(); walker = nextCellInPath; } } else { throw new System.InvalidOperationException($"Filling in until junktion failed :: there should be one next cell in {walker}'s path each time"); } yield return(null); } }
public abstract void SolveMaze(MazeSolvingService service);
public abstract IEnumerator SolveMazeRoutine(MazeSolvingService service);