Example #1
0
        // 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);
        }