public void Solve(IMazeGrid maze, Action <IEnumerable <IMazeCell> > solvedResultCallback) { Graph <IMazeCell> graph = maze.GenerateGraph(); // stack of graph nodes Stack <GraphNode <IMazeCell> > stack = new Stack <GraphNode <IMazeCell> >(); // Routes Collection LinkedList <GraphNode <IMazeCell> > visited = new LinkedList <GraphNode <IMazeCell> >(); GraphNode <IMazeCell> startNode = (GraphNode <IMazeCell>)graph.Nodes.FindByValue(maze.Start); stack.Push(startNode); GraphNode <IMazeCell> currentNode = null; while (stack.Count > 0) { currentNode = stack.Pop(); _logger.LogTrace($"Poped Node: {currentNode.Value.ToString()}"); if (visited.Contains(currentNode)) { continue; } visited.AddFirst(currentNode); if (maze.Finish.Equals(currentNode.Value)) { _logger.LogTrace($"Found Finish Node: {currentNode.Value.ToString()}"); solvedResultCallback(TraceSolvedPath(visited)); } // Examine neighbor nodes foreach (GraphNode <IMazeCell> neighbor in currentNode.Neighbors) { if (!visited.Contains(neighbor)) { stack.Push(neighbor); _logger.LogTrace($"Push Node: {neighbor.Value.ToString()}"); } else { _logger.LogTrace($"Node: {neighbor.Value.ToString()} is visited"); } } } }
public void Solve(IMazeGrid maze, Action <IEnumerable <IMazeCell> > solvedResultCallback) { Graph <IMazeCell> graph = maze.GenerateGraph(); // stack of graph nodes LinkedList <GraphNode <IMazeCell> > visited = new LinkedList <GraphNode <IMazeCell> >(); //collecting all routes GraphNode <IMazeCell> startNode = (GraphNode <IMazeCell>)graph.Nodes.FindByValue(maze.Start); GraphNode <IMazeCell> endNode = (GraphNode <IMazeCell>)graph.Nodes.FindByValue(maze.Finish); visited.AddFirst(startNode); // make the first call BreadthFirst(startNode, endNode, visited, solvedResultCallback); }
public void Solve(IMazeGrid maze, Action <IEnumerable <IMazeCell> > solvedResultCallback) { // the maze graph Graph <IMazeCell> graph = maze.GenerateGraph(); // List of Accepted solutions used to reset the visited nodes List <List <GraphNode <IMazeCell> > > solutions = new List <List <GraphNode <IMazeCell> > >(); // Que of graph nodes Queue <GraphNode <IMazeCell> > queue = new Queue <GraphNode <IMazeCell> >(); // Directory of Predecessor Dictionary <GraphNode <IMazeCell>, GraphNode <IMazeCell> > predecessors = new Dictionary <GraphNode <IMazeCell>, GraphNode <IMazeCell> >(); // List visited nodes List <GraphNode <IMazeCell> > visited = new List <GraphNode <IMazeCell> >(); GraphNode <IMazeCell> currentNode = null; GraphNode <IMazeCell> startNode = (GraphNode <IMazeCell>)graph.Nodes.FindByValue(maze.Start); queue.Enqueue(startNode); while (queue.Count > 0) { currentNode = queue.Dequeue(); _logger.LogTrace($"Dequeue Node({currentNode.Value.ToString()})"); if (visited.Contains(currentNode)) { continue; } visited.Add(currentNode); if (maze.Finish.Equals(currentNode.Value)) { _logger.LogTrace($"Finish Node({currentNode.Value.ToString()})"); IEnumerable <GraphNode <IMazeCell> > solvedPath = TraceSolvedPath(currentNode, predecessors); // callback Action and returns path. List <IMazeCell> cbPath = new List <IMazeCell>(); foreach (var node in solvedPath) { cbPath.Add(node.Value); } solvedResultCallback(cbPath); break; } foreach (GraphNode <IMazeCell> neighbor in currentNode.Neighbors) { if (!visited.Contains(neighbor) && !queue.Contains(neighbor)) { // enquew queue.Enqueue(neighbor); // keep track of Predecessor predecessors[neighbor] = currentNode; _logger.LogTrace($"Enqueue Node: {neighbor.Value.ToString()} Predecessor: {currentNode.Value.ToString()}"); } else { _logger.LogTrace($"Node({neighbor.Value.ToString()}) is visited"); } } } }
/// <summary> /// Construct the maze grid and validate for characters and Start/End Point /// </summary> /// <param name="grid"></param> /// <param name="lines"></param> /// <param name="mazeHeight"></param> /// <param name="mazeWidth"></param> private void LoadMazeMapFromStringList(IMazeGrid grid, List <string> lines, int mazeHeight, int mazeWidth) { _logger.LogInformation($"I found a {mazeWidth} x {mazeHeight} Maze. Moving on to Maze Construction & Validation"); // Initialize 2D array grid.MazeMap = new IMazeCell[mazeHeight, mazeWidth]; grid.Height = mazeHeight; grid.Width = mazeWidth; int i = 0; lines.ForEach(line => { for (int j = 0; j < mazeWidth; j++) { char c = line[j]; if (c == _mazeSettings.WallChar[0]) { grid.MazeMap[i, j] = new MazeCell(i, j) { State = CellState.Wall }; continue; } else if (c == _mazeSettings.StartChar[0]) { grid.MazeMap[i, j] = new MazeCell(i, j) { State = CellState.Path }; if (grid.Start == null) { grid.Start = grid.MazeMap[i, j]; } else { throw new Exception("I do not support more than one starting points"); } } else if (c == _mazeSettings.FinishChar[0]) { grid.MazeMap[i, j] = new MazeCell(i, j) { State = CellState.Path }; if (grid.Finish == null) { grid.Finish = grid.MazeMap[i, j]; } else { throw new Exception("I do not support more than one ending points"); } } else if (c == _mazeSettings.OpenChar[0]) { grid.MazeMap[i, j] = new MazeCell(i, j) { State = CellState.Path }; } else { //Invalid Char. throw new Exception(string.Format("I found a char {0} that this maze was not configured to handle.", c.ToString())); } } i++; }); // Finaly validate that there is a start and an end point if (grid.Start == null || grid.Finish == null) { throw new Exception($"This maze does not have {((grid.Start == null) ? "a start" : "an end")} point"); } }
public void Load(IMazeGrid grid) { if (grid == null) { throw new ArgumentNullException("Maze Grid cannot be null", "grid"); } // Read file into a list of strings and validate lines var lines = new List <string>(); int mazeWidth = 0; int mazeHeight = 0; try { ValidateMazeFile(); _logger.LogInformation($"Reading Maze File: {_mazeSettings.MazeFile}"); using (StreamReader sr = new StreamReader(_mazeSettings.MazeFile)) { while (sr.Peek() >= 0) { // Read the stream to a string, trim to remove white space. string line = sr.ReadLine(); // validate line if (string.IsNullOrWhiteSpace(line)) { throw new InvalidDataException("File can not contain white space"); // can i kick it ? } // Initialize maze width or validate width if (mazeHeight == 0) { mazeWidth = line.Length; } else { if (!mazeWidth.Equals(line.Length)) { throw new InvalidDataException("Lines must have the same width"); } } lines.Add(line); mazeHeight++; } } } catch (Exception e) { // Invalid file or file access _logger.LogError(e.Message); throw new Exception("Invalid file or file access ", e); } if (lines.Count == 0) { throw new Exception("File is empty or does not contain valid lines"); } LoadMazeMapFromStringList(grid, lines, mazeHeight, mazeWidth); }
public void Solve(IMazeGrid maze, Action <IEnumerable <IMazeCell> > solvedResultCallback) { Graph <IMazeCell> graph = maze.GenerateGraph(); GraphNode <IMazeCell> startNode = (GraphNode <IMazeCell>)graph.Nodes.FindByValue(maze.Start); Dictionary <GraphNode <IMazeCell>, GraphNode <IMazeCell> > predecessors = new Dictionary <GraphNode <IMazeCell>, GraphNode <IMazeCell> >(); List <GraphNode <IMazeCell> > nodes = new List <GraphNode <IMazeCell> >(); Dictionary <GraphNode <IMazeCell>, int> distances = new Dictionary <GraphNode <IMazeCell>, int>(); GraphNode <IMazeCell> currentNode = null; // read all nodes and init distances foreach (GraphNode <IMazeCell> vertex in graph.Nodes) { // start node has 0 distance, all over nodes are unknown and set to Max if (vertex.Value.Equals(maze.Start)) { distances[vertex] = 0; } else { distances[vertex] = int.MaxValue; } nodes.Add(vertex); } while (nodes.Count != 0) { // Find current shortest path point to explore nodes.Sort((x, y) => distances[x] - distances[y]); currentNode = nodes[0]; nodes.Remove(currentNode); if (currentNode.Value.Equals(maze.Finish)) { IEnumerable <IMazeCell> solvedPath = TraceSolvedPath(currentNode, predecessors).Reverse(); solvedResultCallback(solvedPath); // Calls the callback Action and returns the path. break; } if (distances[currentNode] == int.MaxValue) { break; } foreach (GraphNode <IMazeCell> neighbor in currentNode.Neighbors) { var indx = currentNode.Neighbors.IndexOf(neighbor); // distance of current node + Neighbors Cost ( Cost = paths between nodes ) int newDistance = distances[currentNode] + currentNode.Costs[indx]; if (newDistance < distances[neighbor]) { distances[neighbor] = newDistance; predecessors[neighbor] = currentNode; } } } }