/// <summary> /// Constructs a new PathFinder instance for the specified Map that will not consider diagonal movements to be valid. /// </summary> /// <param name="map">The Map that this PathFinder instance will run shortest path algorithms on</param> public BasePathfinder(IMap map) { if (map == null) { if (LogFilter.logError) { Debug.LogErrorFormat("Map is null"); } } _map = map; _graph = new EdgeWeightedDigraph(_map.Width * _map.Height); foreach (IBlock block in _map.GetAllBlocks()) { if (block.IsWalkable) { int v = IndexFor(block); foreach (IBlock neighbor in _map.GetBorderBlocksInDiamond(block.X, block.Y, 1)) { if (neighbor.IsWalkable) { int w = IndexFor(neighbor); _graph.AddEdge(new DirectedEdge(v, w, 1.0)); _graph.AddEdge(new DirectedEdge(w, v, 1.0)); } } } } }
// TODO: This method should be private and should be called from the bottom of the constructor /// <summary> /// check optimality conditions: /// </summary> /// <param name="graph">The edge-weighted directed graph</param> /// <param name="sourceVertex">The source vertex to check optimality conditions from</param> private bool Check(EdgeWeightedDigraph graph, int sourceVertex) { if (graph == null) { if (LogFilter.logError) { Debug.LogErrorFormat("EdgeWeightedDigraph cannot be null"); } } if (_distanceTo[sourceVertex] != 0.0 || _edgeTo[sourceVertex] != null) { return(false); } for (int v = 0; v < graph.NumberOfVertices; v++) { if (v == sourceVertex) { continue; } if (_edgeTo[v] == null && _distanceTo[v] != double.PositiveInfinity) { return(false); } } for (int v = 0; v < graph.NumberOfVertices; v++) { foreach (DirectedEdge edge in graph.Adjacent(v)) { int w = edge.To; if (_distanceTo[v] + edge.Weight < _distanceTo[w]) { return(false); } } } for (int w = 0; w < graph.NumberOfVertices; w++) { if (_edgeTo[w] == null) { continue; } DirectedEdge edge = _edgeTo[w]; int v = edge.From; if (w != edge.To) { return(false); } if (_distanceTo[v] + edge.Weight != _distanceTo[w]) { return(false); } } return(true); }
private DijkstraShortestPath(EdgeWeightedDigraph graph, int sourceVertex, int?destinationVertex) { if (graph == null) { if (LogFilter.logError) { Debug.LogErrorFormat("EdgeWeightedDigraph cannot be null"); } } foreach (DirectedEdge edge in graph.Edges()) { if (edge.Weight < 0) { if (LogFilter.logError) { Debug.LogErrorFormat("Edge: '{0}' has negative weight", edge); } } } _distanceTo = new double[graph.NumberOfVertices]; _edgeTo = new DirectedEdge[graph.NumberOfVertices]; for (int v = 0; v < graph.NumberOfVertices; v++) { _distanceTo[v] = Double.PositiveInfinity; } _distanceTo[sourceVertex] = 0.0; _priorityQueue = new IndexMinPriorityQueue <double>(graph.NumberOfVertices); _priorityQueue.Insert(sourceVertex, _distanceTo[sourceVertex]); while (!_priorityQueue.IsEmpty()) { int v = _priorityQueue.DeleteMin(); if (destinationVertex.HasValue && v == destinationVertex.Value) { return; } foreach (DirectedEdge edge in graph.Adjacent(v)) { Relax(edge); } } Check(graph, sourceVertex); }
/// <summary> /// Returns an IEnumerable of DirectedEdges representing a shortest path from the specified sourceVertex to the specified destinationVertex /// This is more efficent than creating a new DijkstraShorestPath instance and calling PathTo( destinationVertex ) when we only /// want a single path from Source to Destination and don't want many paths from the source to multiple different destinations. /// </summary> /// <param name="graph">The edge-weighted directed graph</param> /// <param name="sourceVertex">The source vertext to find a shortest path from</param> /// <param name="destinationVertex">The destination vertex to find a shortest path to</param> public static IEnumerable <DirectedEdge> FindPath(EdgeWeightedDigraph graph, int sourceVertex, int destinationVertex) { var dijkstraShortestPath = new DijkstraShortestPath(graph, sourceVertex, destinationVertex); return(dijkstraShortestPath.PathTo(destinationVertex)); }
/// <summary> /// Computes a shortest paths tree from the specified sourceVertex to every other vertex in the edge-weighted directed graph /// </summary> /// <param name="graph">The edge-weighted directed graph</param> /// <param name="sourceVertex">The source vertex to compute the shortest paths tree from</param> public DijkstraShortestPath(EdgeWeightedDigraph graph, int sourceVertex) : this(graph, sourceVertex, null) { }