diff --git a/Graph/DirectedGraph.cs b/Graph/DirectedGraph.cs index 2ad3687..4519d96 100644 --- a/Graph/DirectedGraph.cs +++ b/Graph/DirectedGraph.cs @@ -224,10 +224,10 @@ namespace MoonTools.Core.Graph } sccs.Clear(); - var preorder = new PooledDictionary(); - var lowlink = new PooledDictionary(); - var sccFound = new PooledDictionary(); - var sccQueue = new PooledStack(); + var preorder = new PooledDictionary(ClearMode.Always); + var lowlink = new PooledDictionary(ClearMode.Always); + var sccFound = new PooledDictionary(ClearMode.Always); + var sccQueue = new PooledStack(ClearMode.Always); uint preorderCounter = 0; @@ -280,7 +280,7 @@ namespace MoonTools.Core.Graph if (lowlink[v] == preorder[v]) { sccFound[v] = true; - var scc = new PooledList + var scc = new PooledList(ClearMode.Always) { v }; diff --git a/Graph/DirectedWeightedGraph.cs b/Graph/DirectedWeightedGraph.cs index 53f877b..58a1827 100644 --- a/Graph/DirectedWeightedGraph.cs +++ b/Graph/DirectedWeightedGraph.cs @@ -112,5 +112,50 @@ namespace MoonTools.Core.Graph yield break; } + + public IEnumerable<(TNode, TNode, int)> DijkstraSingleSourceShortestPath(TNode source) + { + CheckNodes(source); + + var distance = new PooledDictionary(ClearMode.Always); + var previous = new PooledDictionary(ClearMode.Always); + + foreach (var node in Nodes) + { + distance[node] = int.MaxValue; + } + + distance[source] = 0; + + var q = Nodes.ToPooledList(); + + while (q.Count > 0) + { + var node = q.MinBy(n => distance[n]).First(); + q.Remove(node); + if (distance[node] == int.MaxValue) { break; } + + foreach (var neighbor in Neighbors(node)) + { + var alt = distance[node] + Weight(node, neighbor); + if (alt < distance[neighbor]) + { + distance[neighbor] = alt; + previous[neighbor] = node; + } + } + } + + foreach (var node in Nodes) + { + if (!node.Equals(source)) + { + yield return (node, previous[node], distance[node]); + } + } + + distance.Dispose(); + previous.Dispose(); + } } } \ No newline at end of file diff --git a/Graph/UndirectedGraph.cs b/Graph/UndirectedGraph.cs index 6ef0cf9..41568a7 100644 --- a/Graph/UndirectedGraph.cs +++ b/Graph/UndirectedGraph.cs @@ -32,9 +32,9 @@ namespace MoonTools.Core.Graph { get { - var colors = new PooledDictionary(); - var d = new PooledDictionary(); - var partition = new PooledDictionary(); + var colors = new PooledDictionary(ClearMode.Always); + var d = new PooledDictionary(ClearMode.Always); + var partition = new PooledDictionary(ClearMode.Always); foreach (var node in Nodes) { @@ -48,7 +48,7 @@ namespace MoonTools.Core.Graph partition[start] = 1; d[start] = 0; - var stack = new PooledStack(); + var stack = new PooledStack(ClearMode.Always); stack.Push(start); while (stack.Count > 0) diff --git a/test/DirectedWeightedGraph.cs b/test/DirectedWeightedGraph.cs index 34d369a..f204567 100644 --- a/test/DirectedWeightedGraph.cs +++ b/test/DirectedWeightedGraph.cs @@ -221,5 +221,48 @@ namespace Tests // have to call Count() because otherwise the lazy evaluation wont trigger myGraph.Invoking(x => x.AStarShortestPath('a', 'z', (x, y) => 1).Count()).Should().Throw(); } + + [Test] + public void DijkstraSingleSourceShortestPath() + { + var run = new MoveTypeEdgeData { moveType = MoveType.Run }; + var jump = new MoveTypeEdgeData { moveType = MoveType.Jump }; + var wallJump = new MoveTypeEdgeData { moveType = MoveType.WallJump }; + + var myGraph = new DirectedWeightedGraph(); + myGraph.AddNodes('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'); + myGraph.AddEdges( + ('a', 'b', 2, run), + ('a', 'c', 3, run), + ('a', 'e', 4, wallJump), + ('b', 'd', 2, jump), + ('b', 'e', 1, run), + ('c', 'g', 4, jump), + ('c', 'h', 11, run), + ('d', 'c', 3, jump), + ('d', 'f', 2, run), + ('d', 'h', 3, wallJump), + ('e', 'f', 5, run), + ('f', 'd', 2, run), + ('f', 'h', 6, wallJump), + ('g', 'h', 7, run), + ('h', 'f', 1, jump) + ); + + myGraph + .DijkstraSingleSourceShortestPath('a') + .Should() + .Contain(('b', 'a', 2)).And + .Contain(('c', 'a', 3)).And + .Contain(('d', 'b', 4)).And + .Contain(('e', 'b', 3)).And + .Contain(('f', 'd', 6)).And + .Contain(('g', 'c', 7)).And + .Contain(('h', 'd', 7)).And + .HaveCount(7); + + // have to call Count() because otherwise the lazy evaluation wont trigger + myGraph.Invoking(x => x.DijkstraSingleSourceShortestPath('z').Count()).Should().Throw(); + } } } \ No newline at end of file