// To find the path to the solution, simply unwind the solution element tree // from the finsh point to the start using recursion. private void ConstructPathToSolveMaze(MazeSolutionElementTree mazeSolutionElementTree) { if (mazeSolutionElementTree.ParentSolutionElement != null) { ConstructPathToSolveMaze(mazeSolutionElementTree.ParentSolutionElement); } var mazeSolutionElement = new MazeSolutionElement { MazeGridpoint = mazeSolutionElementTree.MazeGridpoint }; PathToSolveMaze.Add(mazeSolutionElement); mazeSolutionElementTree.ParentSolutionElement = null; }
/// <summary> /// Given a direction to proceed, this logic determines what the next maze gridpoint will be. In cases /// where we have reached a dead-end, this may mean backtracking to the last gridpoint where another /// choice was available. /// </summary> private MazeGridpoint DetermineNextMazeGridPoint(MazeGridpoint currentMazeGridpoint, DirectionEnum directionToProceed) { var nextMazeGridpoint = MazeToSolve.ProceedToNewGridpoint(currentMazeGridpoint, directionToProceed); if (MazeToSolve.CheckIfAtDeadEnd(nextMazeGridpoint) || nextMazeGridpoint.HasBeenVisited) { // We have arrived at a dead-end, so this cannot have been the right direction to proceed currentMazeGridpoint.DirectionsAvailable[directionToProceed] = false; if (currentMazeGridpoint.DirectionsAvailable.Count == 1) { // Go back to the last gridpoint where there were more than two choices about the direction to proceed var lastValidMazeSolutionElement = PathToSolveMaze.LastOrDefault(p => p.MazeGridpoint.DirectionsAvailable.Count > 2); if (lastValidMazeSolutionElement == null) { throw new Exception("Maze Solver Error: Sorry, maze could not be solved. The maze image provided may be invalid."); } var directionProceededAtLastValidMazeGridPoint = lastValidMazeSolutionElement.DirectionProceeded; // Since the path resulted in a dead-end, it cannot have been the reight direction to proceed lastValidMazeSolutionElement.MazeGridpoint.DirectionsAvailable[directionProceededAtLastValidMazeGridPoint] = false; // Truncate the path back to the last valid point to take a new direction PathToSolveMaze = PathToSolveMaze.Where(p => p.StepNumber < lastValidMazeSolutionElement.StepNumber).ToList(); return(lastValidMazeSolutionElement.MazeGridpoint); } return(currentMazeGridpoint); } // The step numbers will be indexed starting with zero var stepNumber = PathToSolveMaze.Count; var mazeSolutionElement = new MazeSolutionElement { StepNumber = stepNumber, MazeGridpoint = currentMazeGridpoint, DirectionProceeded = directionToProceed }; PathToSolveMaze.Add(mazeSolutionElement); return(nextMazeGridpoint); }
// This test was used for tracking the progress of some solver algorithms running in release mode public void ConvertTextOutputToSolutionPathOnMazeImage() { const string mazeImageFilePath = @"..\..\..\SampleMazes\Maze2.png"; const string mazeSolutionTextFilePath = @"..\..\..\SampleMazesSolutions\SampleMaze2\WallHugging.txt"; const string mazeImageSolutionFilePath = @"..\..\..\SampleMazesSolutions\SampleMaze2\Maze2SolutionProgress.png"; var mazeReader = new MazeReaderUtility(mazeImageFilePath); var maze = mazeReader.ReadInMazeImage(); var fileLines = File.ReadAllLines(mazeSolutionTextFilePath); var count = fileLines.Count(); var mazeSolutionPath = new List <MazeSolutionElement>(); for (var i = 0; i < count; i++) { var line = fileLines[i]; var splitLine = line.Split(' ', ','); var xPosition = Convert.ToInt32(splitLine[2]); var yPosition = Convert.ToInt32(splitLine[6]); var coordinate = new CartesianCoordinate(xPosition, yPosition); var mazeGridpoint = maze.MazeGridpoints[coordinate]; var solutionElement = new MazeSolutionElement { MazeGridpoint = mazeGridpoint, }; mazeSolutionPath.Add(solutionElement); fileLines[i] = null; } var mazeSolution = new MazeSolution(maze) { PathToSolveMaze = mazeSolutionPath }; var mazeWriter = new MazeWriterUtility(mazeImageSolutionFilePath, mazeSolution.MazeToSolve); mazeSolution.MarkSolutionPath(); mazeWriter.SaveMazeImage(); }
private void ConstructPathToSolveMaze(MazeSolutionElement mazeSolutionElement) { var pathToSolveMaze = new List <MazeSolutionElement>(); pathToSolveMaze.Add(mazeSolutionElement); // Go back from parent to parent to find the tree that results in a solution // The starting solution element will have a parent that is null while (pathToSolveMaze.Last().ParentMazeGridpoint != null) { var previousMazeGridpoint = mazeSolutionElement.ParentMazeGridpoint; var previousMazeSolutionElement = PathToSolveMaze.Single(m => m.MazeGridpoint == previousMazeGridpoint); pathToSolveMaze.Add(previousMazeSolutionElement); mazeSolutionElement = previousMazeSolutionElement; } PathToSolveMaze = pathToSolveMaze; }
/// <summary> /// Solves the maze using a brute force algorithm approach. /// </summary> public override void SolveMaze() { // Apply all pre-treament logics, if any PreTreatmentLogics.ForEach(p => p.PreTreatMazeToSolve()); // Set all parent gridpoints to null at the start var currentMazeGridpoint = MazeToSolve.MazeGridpoints.Values.First(m => m.IsStartPoint && m.DirectionsAvailable.Count > 0); // Keep on looking so long as we haven't reached the finish while (!MazeToSolve.CheckIfAtFinish(currentMazeGridpoint)) { currentMazeGridpoint.HasBeenVisited = true; // Picked a direction and go in that direction var directionToProceed = DirectionPickerLogic.PickDirectionToProceed(PathToSolveMaze, currentMazeGridpoint); if (directionToProceed == DirectionEnum.None) { throw new Exception("Maze Solver Error: Sorry, maze could not be solved. The maze image provided may be invalid."); } currentMazeGridpoint = DetermineNextMazeGridPoint(currentMazeGridpoint, directionToProceed); Console.WriteLine("X : " + currentMazeGridpoint.Position.X + ", Y : " + currentMazeGridpoint.Position.Y + " Direction : " + directionToProceed); MazeToSolve.NotifyMazeHasBeenUpdated(); MazeToSolve.NotifyMazeToBeRedrawnUpdated(); } // Once out of the loop, the current gridpoint will be the final gridpoint var finalMazeSolutionElement = new MazeSolutionElement { StepNumber = PathToSolveMaze.Count, MazeGridpoint = currentMazeGridpoint, DirectionProceeded = DirectionEnum.None }; PathToSolveMaze.Add(finalMazeSolutionElement); }