graph logic depends on MoonTools.Core.Graph
							parent
							
								
									85f99a565c
								
							
						
					
					
						commit
						790e36b2d3
					
				|  | @ -11,8 +11,10 @@ namespace Encompass | |||
|     /// They are responsible for reading the World state, reading messages, emitting messages, and creating or mutating Entities and Components. | ||||
|     /// Engines run once per World Update. | ||||
|     /// </summary> | ||||
|     public abstract class Engine | ||||
|     public abstract class Engine : IEquatable<Engine> | ||||
|     { | ||||
|         public Guid ID; | ||||
| 
 | ||||
|         internal readonly HashSet<Type> sendTypes = new HashSet<Type>(); | ||||
|         internal readonly HashSet<Type> receiveTypes = new HashSet<Type>(); | ||||
|         internal readonly Dictionary<Type, int> writePriorities = new Dictionary<Type, int>(); | ||||
|  | @ -24,6 +26,8 @@ namespace Encompass | |||
| 
 | ||||
|         protected Engine() | ||||
|         { | ||||
|             ID = Guid.NewGuid(); | ||||
| 
 | ||||
|             var sendsAttribute = GetType().GetCustomAttribute<Sends>(false); | ||||
|             if (sendsAttribute != null) | ||||
|             { | ||||
|  | @ -62,6 +66,26 @@ namespace Encompass | |||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public override bool Equals(object obj) | ||||
|         { | ||||
|             if (obj is Engine) | ||||
|             { | ||||
|                 return this.Equals((Engine)obj); | ||||
|             } | ||||
| 
 | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         public bool Equals(Engine other) | ||||
|         { | ||||
|             return other.ID == ID; | ||||
|         } | ||||
| 
 | ||||
|         public override int GetHashCode() | ||||
|         { | ||||
|             return ID.GetHashCode(); | ||||
|         } | ||||
| 
 | ||||
|         internal void AssignEntityManager(EntityManager entityManager) | ||||
|         { | ||||
|             this.entityManager = entityManager; | ||||
|  |  | |||
|  | @ -1,420 +0,0 @@ | |||
| using System; | ||||
| using System.Collections; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| 
 | ||||
| namespace Encompass | ||||
| { | ||||
|     public enum SearchSymbol | ||||
|     { | ||||
|         start, | ||||
|         finish | ||||
|     } | ||||
| 
 | ||||
|     public class DirectedGraph<T> | ||||
|     { | ||||
|         private class SimpleCycleComparer : IEqualityComparer<IEnumerable<T>> | ||||
|         { | ||||
|             public bool Equals(IEnumerable<T> x, IEnumerable<T> y) | ||||
|             { | ||||
|                 return x.SequenceEqual(y); | ||||
|             } | ||||
| 
 | ||||
|             public int GetHashCode(IEnumerable<T> obj) | ||||
|             { | ||||
|                 return obj.Aggregate(0, (current, next) => current.GetHashCode() ^ next.GetHashCode()); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         protected List<T> _vertices = new List<T>(); | ||||
|         protected Dictionary<T, HashSet<T>> _neighbors = new Dictionary<T, HashSet<T>>(); | ||||
| 
 | ||||
|         public IEnumerable<T> Vertices { get { return _vertices; } } | ||||
| 
 | ||||
|         /* | ||||
|          * GRAPH STRUCTURE METHODS | ||||
|          */ | ||||
| 
 | ||||
|         public void AddVertex(T vertex) | ||||
|         { | ||||
|             if (!VertexExists(vertex)) | ||||
|             { | ||||
|                 _vertices.Add(vertex); | ||||
|                 _neighbors.Add(vertex, new HashSet<T>()); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public void AddVertices(params T[] vertices) | ||||
|         { | ||||
|             foreach (var vertex in vertices) | ||||
|             { | ||||
|                 AddVertex(vertex); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public bool VertexExists(T vertex) | ||||
|         { | ||||
|             return Vertices.Contains(vertex); | ||||
|         } | ||||
| 
 | ||||
|         public void RemoveVertex(T vertex) | ||||
|         { | ||||
|             var edgesToRemove = new List<Tuple<T, T>>(); | ||||
| 
 | ||||
|             if (VertexExists(vertex)) | ||||
|             { | ||||
|                 foreach (var entry in _neighbors) | ||||
|                 { | ||||
|                     if (entry.Value.Contains(vertex)) | ||||
|                     { | ||||
|                         edgesToRemove.Add(Tuple.Create(entry.Key, vertex)); | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 foreach (var edge in edgesToRemove) | ||||
|                 { | ||||
|                     RemoveEdge(edge.Item1, edge.Item2); | ||||
|                 } | ||||
| 
 | ||||
|                 _vertices.Remove(vertex); | ||||
|                 _neighbors.Remove(vertex); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public void AddEdge(T v, T u) | ||||
|         { | ||||
|             if (VertexExists(v) && VertexExists(u)) | ||||
|             { | ||||
|                 _neighbors[v].Add(u); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public void AddEdges(params Tuple<T, T>[] edges) | ||||
|         { | ||||
|             foreach (var edge in edges) | ||||
|             { | ||||
|                 AddEdge(edge.Item1, edge.Item2); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public void RemoveEdge(T v, T u) | ||||
|         { | ||||
|             _neighbors[v].Remove(u); | ||||
|         } | ||||
| 
 | ||||
|         public IEnumerable<T> Neighbors(T vertex) | ||||
|         { | ||||
|             if (VertexExists(vertex)) | ||||
|             { | ||||
|                 return _neighbors[vertex]; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return Enumerable.Empty<T>(); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         /* | ||||
|          * GRAPH ANALYSIS METHODS | ||||
|          */ | ||||
| 
 | ||||
|         public Dictionary<T, Dictionary<SearchSymbol, uint>> NodeDFS() | ||||
|         { | ||||
|             var discovered = new HashSet<T>(); | ||||
|             uint time = 0; | ||||
|             var output = new Dictionary<T, Dictionary<SearchSymbol, uint>>(); | ||||
| 
 | ||||
|             foreach (var vertex in Vertices) | ||||
|             { | ||||
|                 output.Add(vertex, new Dictionary<SearchSymbol, uint>()); | ||||
|             } | ||||
| 
 | ||||
|             void dfsHelper(T v) | ||||
|             { | ||||
|                 discovered.Add(v); | ||||
|                 time++; | ||||
|                 output[v].Add(SearchSymbol.start, time); | ||||
| 
 | ||||
|                 foreach (var neighbor in Neighbors(v)) | ||||
|                 { | ||||
|                     if (!discovered.Contains(neighbor)) | ||||
|                     { | ||||
|                         dfsHelper(neighbor); | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 time++; | ||||
|                 output[v].Add(SearchSymbol.finish, time); | ||||
|             } | ||||
| 
 | ||||
|             foreach (var vertex in Vertices) | ||||
|             { | ||||
|                 if (!discovered.Contains(vertex)) | ||||
|                 { | ||||
|                     dfsHelper(vertex); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             return output; | ||||
|         } | ||||
| 
 | ||||
|         public bool Cyclic() | ||||
|         { | ||||
|             return StronglyConnectedComponents().Any((scc) => scc.Count() > 1); | ||||
|         } | ||||
| 
 | ||||
|         public IEnumerable<T> TopologicalSort() | ||||
|         { | ||||
|             var dfs = NodeDFS(); | ||||
|             var priority = new SortedList<uint, T>(); | ||||
|             foreach (var entry in dfs) | ||||
|             { | ||||
|                 priority.Add(entry.Value[SearchSymbol.finish], entry.Key); | ||||
|             } | ||||
|             return priority.Values.Reverse(); | ||||
|         } | ||||
| 
 | ||||
|         public IEnumerable<IEnumerable<T>> StronglyConnectedComponents() | ||||
|         { | ||||
|             var preorder = new Dictionary<T, uint>(); | ||||
|             var lowlink = new Dictionary<T, uint>(); | ||||
|             var sccFound = new Dictionary<T, bool>(); | ||||
|             var sccQueue = new Stack<T>(); | ||||
| 
 | ||||
|             var result = new List<List<T>>(); | ||||
| 
 | ||||
|             uint preorderCounter = 0; | ||||
| 
 | ||||
|             foreach (var source in Vertices) | ||||
|             { | ||||
|                 if (!sccFound.ContainsKey(source)) | ||||
|                 { | ||||
|                     var queue = new Stack<T>(); | ||||
|                     queue.Push(source); | ||||
| 
 | ||||
|                     while (queue.Count > 0) | ||||
|                     { | ||||
|                         var v = queue.Peek(); | ||||
|                         if (!preorder.ContainsKey(v)) | ||||
|                         { | ||||
|                             preorderCounter++; | ||||
|                             preorder[v] = preorderCounter; | ||||
|                         } | ||||
| 
 | ||||
|                         var done = true; | ||||
|                         var vNeighbors = Neighbors(v); | ||||
|                         foreach (var w in vNeighbors) | ||||
|                         { | ||||
|                             if (!preorder.ContainsKey(w)) | ||||
|                             { | ||||
|                                 queue.Push(w); | ||||
|                                 done = false; | ||||
|                                 break; | ||||
|                             } | ||||
|                         } | ||||
| 
 | ||||
|                         if (done) | ||||
|                         { | ||||
|                             lowlink[v] = preorder[v]; | ||||
|                             foreach (var w in vNeighbors) | ||||
|                             { | ||||
|                                 if (!sccFound.ContainsKey(w)) | ||||
|                                 { | ||||
|                                     if (preorder[w] > preorder[v]) | ||||
|                                     { | ||||
|                                         lowlink[v] = Math.Min(lowlink[v], lowlink[w]); | ||||
|                                     } | ||||
|                                     else | ||||
|                                     { | ||||
|                                         lowlink[v] = Math.Min(lowlink[v], preorder[w]); | ||||
|                                     } | ||||
|                                 } | ||||
|                             } | ||||
|                             queue.Pop(); | ||||
|                             if (lowlink[v] == preorder[v]) | ||||
|                             { | ||||
|                                 sccFound[v] = true; | ||||
|                                 var scc = new List<T> | ||||
|                                 { | ||||
|                                     v | ||||
|                                 }; | ||||
|                                 while (sccQueue.Count > 0 && preorder[sccQueue.Peek()] > preorder[v]) | ||||
|                                 { | ||||
|                                     var k = sccQueue.Pop(); | ||||
|                                     sccFound[k] = true; | ||||
|                                     scc.Add(k); | ||||
|                                 } | ||||
|                                 result.Add(scc); | ||||
|                             } | ||||
|                             else | ||||
|                             { | ||||
|                                 sccQueue.Push(v); | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             return result; | ||||
|         } | ||||
| 
 | ||||
|         public IEnumerable<IEnumerable<T>> SimpleCycles() | ||||
|         { | ||||
|             void unblock(T thisnode, HashSet<T> blocked, Dictionary<T, HashSet<T>> B) | ||||
|             { | ||||
|                 var stack = new Stack<T>(); | ||||
|                 stack.Push(thisnode); | ||||
| 
 | ||||
|                 while (stack.Count > 0) | ||||
|                 { | ||||
|                     var node = stack.Pop(); | ||||
|                     if (blocked.Contains(thisnode)) | ||||
|                     { | ||||
|                         blocked.Remove(thisnode); | ||||
|                         if (B.ContainsKey(node)) | ||||
|                         { | ||||
|                             foreach (var n in B[node]) | ||||
|                             { | ||||
|                                 if (!stack.Contains(n)) | ||||
|                                 { | ||||
|                                     stack.Push(n); | ||||
|                                 } | ||||
|                             } | ||||
|                             B[node].Clear(); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             List<List<T>> result = new List<List<T>>(); | ||||
|             var subGraph = Clone(); | ||||
| 
 | ||||
|             var sccs = new Stack<IEnumerable<T>>(); | ||||
|             foreach (var scc in StronglyConnectedComponents()) | ||||
|             { | ||||
|                 sccs.Push(scc); | ||||
|             } | ||||
| 
 | ||||
|             while (sccs.Count > 0) | ||||
|             { | ||||
|                 var scc = new Stack<T>(sccs.Pop()); | ||||
|                 var startNode = scc.Pop(); | ||||
|                 var path = new Stack<T>(); | ||||
|                 path.Push(startNode); | ||||
|                 var blocked = new HashSet<T> | ||||
|                 { | ||||
|                     startNode | ||||
|                 }; | ||||
|                 var closed = new HashSet<T>(); | ||||
|                 var B = new Dictionary<T, HashSet<T>>(); | ||||
|                 var stack = new Stack<Tuple<T, Stack<T>>>(); | ||||
|                 stack.Push(Tuple.Create(startNode, new Stack<T>(subGraph.Neighbors(startNode)))); | ||||
| 
 | ||||
|                 while (stack.Count > 0) | ||||
|                 { | ||||
|                     var entry = stack.Peek(); | ||||
|                     var thisnode = entry.Item1; | ||||
|                     var neighbors = entry.Item2; | ||||
| 
 | ||||
|                     if (neighbors.Count > 0) | ||||
|                     { | ||||
|                         var nextNode = neighbors.Pop(); | ||||
| 
 | ||||
|                         if (nextNode.Equals(startNode)) | ||||
|                         { | ||||
|                             var resultPath = new List<T>(); | ||||
|                             foreach (var v in path) | ||||
|                             { | ||||
|                                 resultPath.Add(v); | ||||
|                             } | ||||
|                             result.Add(resultPath); | ||||
|                             foreach (var v in path) | ||||
|                             { | ||||
|                                 closed.Add(v); | ||||
|                             } | ||||
|                         } | ||||
|                         else if (!blocked.Contains(nextNode)) | ||||
|                         { | ||||
|                             path.Push(nextNode); | ||||
|                             stack.Push(Tuple.Create(nextNode, new Stack<T>(subGraph.Neighbors(nextNode)))); | ||||
|                             closed.Remove(nextNode); | ||||
|                             blocked.Add(nextNode); | ||||
|                             continue; | ||||
|                         } | ||||
|                     } | ||||
| 
 | ||||
|                     if (neighbors.Count == 0) | ||||
|                     { | ||||
|                         if (closed.Contains(thisnode)) | ||||
|                         { | ||||
|                             unblock(thisnode, blocked, B); | ||||
|                         } | ||||
|                         else | ||||
|                         { | ||||
|                             foreach (var neighbor in subGraph.Neighbors(thisnode)) | ||||
|                             { | ||||
|                                 if (!B.ContainsKey(neighbor)) | ||||
|                                 { | ||||
|                                     B[neighbor] = new HashSet<T>(); | ||||
|                                 } | ||||
|                                 B[neighbor].Add(thisnode); | ||||
|                             } | ||||
|                         } | ||||
| 
 | ||||
|                         stack.Pop(); | ||||
|                         path.Pop(); | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 subGraph.RemoveVertex(startNode); | ||||
|                 var H = subGraph.SubGraph(scc.ToArray()); | ||||
|                 var HSccs = H.StronglyConnectedComponents(); | ||||
|                 foreach (var HScc in HSccs) | ||||
|                 { | ||||
|                     sccs.Push(HScc); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             return result.Distinct(new SimpleCycleComparer()); | ||||
|         } | ||||
| 
 | ||||
|         public DirectedGraph<T> Clone() | ||||
|         { | ||||
|             var clone = new DirectedGraph<T>(); | ||||
|             clone.AddVertices(Vertices.ToArray()); | ||||
| 
 | ||||
|             foreach (var v in Vertices) | ||||
|             { | ||||
|                 foreach (var n in Neighbors(v)) | ||||
|                 { | ||||
|                     clone.AddEdge(v, n); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             return clone; | ||||
|         } | ||||
| 
 | ||||
|         public DirectedGraph<T> SubGraph(params T[] subVertices) | ||||
|         { | ||||
|             var subGraph = new DirectedGraph<T>(); | ||||
|             subGraph.AddVertices(subVertices.ToArray()); | ||||
| 
 | ||||
|             foreach (var v in Vertices) | ||||
|             { | ||||
|                 if (Vertices.Contains(v)) | ||||
|                 { | ||||
|                     var neighbors = Neighbors(v); | ||||
|                     foreach (var u in neighbors) | ||||
|                     { | ||||
|                         if (subVertices.Contains(u)) | ||||
|                         { | ||||
|                             subGraph.AddEdge(v, u); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             return subGraph; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -4,6 +4,8 @@ using System.Reflection; | |||
| using System.Linq; | ||||
| using Encompass.Exceptions; | ||||
| using Encompass.Engines; | ||||
| using MoonTools.Core.Graph; | ||||
| using MoonTools.Core.Graph.Extensions; | ||||
| 
 | ||||
| namespace Encompass | ||||
| { | ||||
|  | @ -18,7 +20,7 @@ namespace Encompass | |||
|     public class WorldBuilder | ||||
|     { | ||||
|         private readonly List<Engine> engines = new List<Engine>(); | ||||
|         private readonly DirectedGraph<Engine> engineGraph = new DirectedGraph<Engine>(); | ||||
|         private readonly DirectedGraph<Engine, Unit> engineGraph = GraphBuilder.DirectedGraph<Engine>(); | ||||
| 
 | ||||
|         private readonly ComponentManager componentManager; | ||||
|         private readonly EntityManager entityManager; | ||||
|  | @ -102,7 +104,7 @@ namespace Encompass | |||
|             engine.AssignComponentMessageManager(componentMessageManager); | ||||
| 
 | ||||
|             engines.Add(engine); | ||||
|             engineGraph.AddVertex(engine); | ||||
|             engineGraph.AddNode(engine); | ||||
| 
 | ||||
|             var messageReceiveTypes = engine.receiveTypes; | ||||
|             var messageSendTypes = engine.sendTypes; | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
|   <PropertyGroup> | ||||
|     <TargetFramework>netstandard2.0</TargetFramework> | ||||
|     <RootNamespace>Encompass</RootNamespace> | ||||
|  | @ -24,5 +24,6 @@ | |||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <PackageReference Include="Collections.Pooled" Version="1.0.82"/> | ||||
|     <PackageReference Include="MoonTools.Core.Graph" Version="1.0.0"/> | ||||
|   </ItemGroup> | ||||
| </Project> | ||||
| </Project> | ||||
|  | @ -1,374 +0,0 @@ | |||
| using NUnit.Framework; | ||||
| using FluentAssertions; | ||||
| 
 | ||||
| using System; | ||||
| using System.Linq; | ||||
| 
 | ||||
| using Encompass; | ||||
| using System.Collections.Generic; | ||||
| 
 | ||||
| namespace Tests | ||||
| { | ||||
|     public class DirectedGraphTest | ||||
|     { | ||||
|         [Test] | ||||
|         public void AddVertex() | ||||
|         { | ||||
|             var myGraph = new DirectedGraph<int>(); | ||||
|             myGraph.AddVertex(4); | ||||
| 
 | ||||
|             Assert.That(myGraph.Vertices, Does.Contain(4)); | ||||
|         } | ||||
| 
 | ||||
|         [Test] | ||||
|         public void AddVertices() | ||||
|         { | ||||
|             var myGraph = new DirectedGraph<int>(); | ||||
|             myGraph.AddVertices(4, 20, 69); | ||||
| 
 | ||||
|             Assert.IsTrue(myGraph.VertexExists(4)); | ||||
|             Assert.IsTrue(myGraph.VertexExists(20)); | ||||
|             Assert.IsTrue(myGraph.VertexExists(69)); | ||||
|         } | ||||
| 
 | ||||
|         [Test] | ||||
|         public void AddEdge() | ||||
|         { | ||||
|             var myGraph = new DirectedGraph<int>(); | ||||
|             myGraph.AddVertices(5, 6); | ||||
|             myGraph.AddEdge(5, 6); | ||||
| 
 | ||||
|             Assert.That(myGraph.Neighbors(5), Does.Contain(6)); | ||||
|         } | ||||
| 
 | ||||
|         [Test] | ||||
|         public void AddEdges() | ||||
|         { | ||||
|             var myGraph = new DirectedGraph<int>(); | ||||
|             myGraph.AddVertices(1, 2, 3, 4); | ||||
|             myGraph.AddEdges( | ||||
|                 Tuple.Create(1, 2), | ||||
|                 Tuple.Create(2, 3), | ||||
|                 Tuple.Create(2, 4), | ||||
|                 Tuple.Create(3, 4) | ||||
|             ); | ||||
| 
 | ||||
|             Assert.That(myGraph.Neighbors(1), Does.Contain(2)); | ||||
|             Assert.That(myGraph.Neighbors(2), Does.Contain(3)); | ||||
|             Assert.That(myGraph.Neighbors(2), Does.Contain(4)); | ||||
|             Assert.That(myGraph.Neighbors(3), Does.Contain(4)); | ||||
|             Assert.That(myGraph.Neighbors(1), Does.Not.Contain(4)); | ||||
|         } | ||||
| 
 | ||||
|         [Test] | ||||
|         public void RemoveEdge() | ||||
|         { | ||||
|             var myGraph = new DirectedGraph<int>(); | ||||
|             myGraph.AddVertices(1, 2, 3, 4); | ||||
|             myGraph.AddEdges( | ||||
|                 Tuple.Create(1, 2), | ||||
|                 Tuple.Create(2, 3), | ||||
|                 Tuple.Create(2, 4), | ||||
|                 Tuple.Create(3, 4) | ||||
|             ); | ||||
| 
 | ||||
|             myGraph.RemoveEdge(2, 3); | ||||
| 
 | ||||
|             Assert.That(myGraph.Neighbors(2), Does.Not.Contain(3)); | ||||
|             Assert.That(myGraph.Neighbors(2), Does.Contain(4)); | ||||
|         } | ||||
| 
 | ||||
|         [Test] | ||||
|         public void RemoveVertex() | ||||
|         { | ||||
|             var myGraph = new DirectedGraph<int>(); | ||||
|             myGraph.AddVertices(1, 2, 3, 4); | ||||
|             myGraph.AddEdges( | ||||
|                 Tuple.Create(1, 2), | ||||
|                 Tuple.Create(2, 3), | ||||
|                 Tuple.Create(2, 4), | ||||
|                 Tuple.Create(3, 4) | ||||
|             ); | ||||
| 
 | ||||
|             myGraph.RemoveVertex(2); | ||||
| 
 | ||||
|             myGraph.Vertices.Should().NotContain(2); | ||||
|             myGraph.Neighbors(1).Should().NotContain(2); | ||||
|             myGraph.Neighbors(3).Should().Contain(4); | ||||
|         } | ||||
| 
 | ||||
|         [Test] | ||||
|         public void NodeDFS() | ||||
|         { | ||||
|             var myGraph = new DirectedGraph<char>(); | ||||
|             myGraph.AddVertices('a', 'b', 'c', 'd'); | ||||
|             myGraph.AddEdges( | ||||
|                 Tuple.Create('a', 'b'), | ||||
|                 Tuple.Create('a', 'c'), | ||||
|                 Tuple.Create('b', 'd') | ||||
|             ); | ||||
| 
 | ||||
|             var result = myGraph.NodeDFS(); | ||||
| 
 | ||||
|             Assert.That(result['a'][SearchSymbol.start], Is.EqualTo(1)); | ||||
|             Assert.That(result['a'][SearchSymbol.finish], Is.EqualTo(8)); | ||||
| 
 | ||||
|             Assert.That(result['b'][SearchSymbol.start], Is.EqualTo(2)); | ||||
|             Assert.That(result['b'][SearchSymbol.finish], Is.EqualTo(5)); | ||||
| 
 | ||||
|             Assert.That(result['c'][SearchSymbol.start], Is.EqualTo(6)); | ||||
|             Assert.That(result['c'][SearchSymbol.finish], Is.EqualTo(7)); | ||||
| 
 | ||||
|             Assert.That(result['d'][SearchSymbol.start], Is.EqualTo(3)); | ||||
|             Assert.That(result['d'][SearchSymbol.finish], Is.EqualTo(4)); | ||||
|         } | ||||
| 
 | ||||
|         [Test] | ||||
|         public void TopologicalSortSimple() | ||||
|         { | ||||
|             var simpleGraph = new DirectedGraph<char>(); | ||||
|             simpleGraph.AddVertices('a', 'b', 'c', 'd'); | ||||
|             simpleGraph.AddEdges( | ||||
|                 Tuple.Create('a', 'b'), | ||||
|                 Tuple.Create('a', 'c'), | ||||
|                 Tuple.Create('b', 'a'), | ||||
|                 Tuple.Create('b', 'd') | ||||
|             ); | ||||
| 
 | ||||
|             Assert.That(simpleGraph.TopologicalSort(), Is.EqualTo(new char[] { 'a', 'c', 'b', 'd' })); | ||||
|         } | ||||
| 
 | ||||
|         [Test] | ||||
|         public void TopologicalSortComplex() | ||||
|         { | ||||
|             var complexGraph = new DirectedGraph<char>(); | ||||
|             complexGraph.AddVertices('a', 'b', 'c', 'd', 'e', 'f', 'g', 't', 'm'); | ||||
|             complexGraph.AddEdges( | ||||
|                 Tuple.Create('a', 'b'), | ||||
|                 Tuple.Create('a', 'c'), | ||||
|                 Tuple.Create('a', 'd'), | ||||
|                 Tuple.Create('b', 'f'), | ||||
|                 Tuple.Create('b', 'g'), | ||||
|                 Tuple.Create('c', 'g'), | ||||
|                 Tuple.Create('e', 't'), | ||||
|                 Tuple.Create('t', 'm') | ||||
|             ); | ||||
| 
 | ||||
|             Assert.That( | ||||
|                 complexGraph.TopologicalSort(), | ||||
|                 Is.EqualTo(new char[] { 'e', 't', 'm', 'a', 'd', 'c', 'b', 'g', 'f' }) | ||||
|             ); | ||||
|         } | ||||
| 
 | ||||
|         [Test] | ||||
|         public void StronglyConnectedComponentsSimple() | ||||
|         { | ||||
|             var simpleGraph = new DirectedGraph<int>(); | ||||
|             simpleGraph.AddVertices(1, 2, 3); | ||||
|             simpleGraph.AddEdges( | ||||
|                 Tuple.Create(1, 2), | ||||
|                 Tuple.Create(2, 3), | ||||
|                 Tuple.Create(3, 2), | ||||
|                 Tuple.Create(2, 1) | ||||
|             ); | ||||
| 
 | ||||
|             var result = simpleGraph.StronglyConnectedComponents(); | ||||
|             var scc = new int[] { 1, 2, 3 }; | ||||
| 
 | ||||
|             result.Should().ContainEquivalentOf(scc); | ||||
|             Assert.That(result.Count, Is.EqualTo(1)); | ||||
|         } | ||||
| 
 | ||||
|         [Test] | ||||
|         public void StronglyConnectedComponentsMedium() | ||||
|         { | ||||
|             var mediumGraph = new DirectedGraph<int>(); | ||||
|             mediumGraph.AddVertices(1, 2, 3, 4); | ||||
|             mediumGraph.AddEdges( | ||||
|                 Tuple.Create(1, 2), | ||||
|                 Tuple.Create(1, 3), | ||||
|                 Tuple.Create(1, 4), | ||||
|                 Tuple.Create(4, 2), | ||||
|                 Tuple.Create(3, 4), | ||||
|                 Tuple.Create(2, 3) | ||||
|             ); | ||||
| 
 | ||||
|             var result = mediumGraph.StronglyConnectedComponents(); | ||||
|             var sccA = new int[] { 2, 3, 4 }; | ||||
|             var sccB = new int[] { 1 }; | ||||
| 
 | ||||
|             result.Should().ContainEquivalentOf(sccA); | ||||
|             result.Should().ContainEquivalentOf(sccB); | ||||
|             Assert.That(result.Count, Is.EqualTo(2)); | ||||
|         } | ||||
| 
 | ||||
|         [Test] | ||||
|         public void StronglyConnectedComponentsComplex() | ||||
|         { | ||||
|             var complexGraph = new DirectedGraph<int>(); | ||||
|             complexGraph.AddVertices(1, 2, 3, 4, 5, 6, 7, 8); | ||||
|             complexGraph.AddEdges( | ||||
|                 Tuple.Create(1, 2), | ||||
|                 Tuple.Create(2, 3), | ||||
|                 Tuple.Create(2, 8), | ||||
|                 Tuple.Create(3, 4), | ||||
|                 Tuple.Create(3, 7), | ||||
|                 Tuple.Create(4, 5), | ||||
|                 Tuple.Create(5, 3), | ||||
|                 Tuple.Create(5, 6), | ||||
|                 Tuple.Create(7, 4), | ||||
|                 Tuple.Create(7, 6), | ||||
|                 Tuple.Create(8, 1), | ||||
|                 Tuple.Create(8, 7) | ||||
|             ); | ||||
| 
 | ||||
|             var result = complexGraph.StronglyConnectedComponents(); | ||||
|             var sccA = new int[] { 3, 4, 5, 7 }; | ||||
|             var sccB = new int[] { 1, 2, 8 }; | ||||
|             var sccC = new int[] { 6 }; | ||||
| 
 | ||||
|             result.Should().ContainEquivalentOf(sccA); | ||||
|             result.Should().ContainEquivalentOf(sccB); | ||||
|             result.Should().ContainEquivalentOf(sccC); | ||||
|             Assert.That(result.Count, Is.EqualTo(3)); | ||||
|         } | ||||
| 
 | ||||
|         [Test] | ||||
|         public void Clone() | ||||
|         { | ||||
|             var myGraph = new DirectedGraph<int>(); | ||||
|             myGraph.AddVertices(1, 2, 3, 4); | ||||
|             myGraph.AddEdges( | ||||
|                 Tuple.Create(1, 1), | ||||
|                 Tuple.Create(1, 2), | ||||
|                 Tuple.Create(2, 3), | ||||
|                 Tuple.Create(2, 1), | ||||
|                 Tuple.Create(3, 4) | ||||
|             ); | ||||
| 
 | ||||
|             var clone = myGraph.Clone(); | ||||
|             Assert.That(clone, Is.Not.EqualTo(myGraph)); | ||||
|             clone.Vertices.Should().BeEquivalentTo(1, 2, 3, 4); | ||||
|             clone.Neighbors(1).Should().BeEquivalentTo(1, 2); | ||||
|             clone.Neighbors(2).Should().BeEquivalentTo(3, 1); | ||||
|             clone.Neighbors(3).Should().BeEquivalentTo(4); | ||||
|         } | ||||
| 
 | ||||
|         [Test] | ||||
|         public void SubGraph() | ||||
|         { | ||||
|             var myGraph = new DirectedGraph<int>(); | ||||
|             myGraph.AddVertices(1, 2, 3, 4); | ||||
|             myGraph.AddEdges( | ||||
|                 Tuple.Create(1, 1), | ||||
|                 Tuple.Create(1, 2), | ||||
|                 Tuple.Create(2, 3), | ||||
|                 Tuple.Create(2, 1), | ||||
|                 Tuple.Create(3, 4) | ||||
|             ); | ||||
| 
 | ||||
|             var subGraph = myGraph.SubGraph(1, 2, 3); | ||||
|             subGraph.Vertices.Should().BeEquivalentTo(1, 2, 3); | ||||
|             subGraph.Neighbors(1).Should().BeEquivalentTo(1, 2); | ||||
|             subGraph.Neighbors(2).Should().BeEquivalentTo(1, 3); | ||||
|             subGraph.Neighbors(3).Should().NotContain(4); | ||||
|         } | ||||
| 
 | ||||
|         [Test] | ||||
|         public void SimpleCyclesSimple() | ||||
|         { | ||||
|             var myGraph = new DirectedGraph<int>(); | ||||
|             myGraph.AddVertices(0, 1, 2); | ||||
|             myGraph.AddEdges( | ||||
|                 Tuple.Create(0, 0), | ||||
|                 Tuple.Create(0, 1), | ||||
|                 Tuple.Create(0, 2), | ||||
|                 Tuple.Create(1, 2), | ||||
|                 Tuple.Create(2, 0), | ||||
|                 Tuple.Create(2, 1), | ||||
|                 Tuple.Create(2, 2) | ||||
|             ); | ||||
| 
 | ||||
|             var result = myGraph.SimpleCycles(); | ||||
| 
 | ||||
|             var cycleA = new int[] { 0 }; | ||||
|             var cycleB = new int[] { 0, 1, 2 }; | ||||
|             var cycleC = new int[] { 0, 2 }; | ||||
|             var cycleD = new int[] { 1, 2 }; | ||||
|             var cycleE = new int[] { 2 }; | ||||
| 
 | ||||
|             result.Should().ContainEquivalentOf(cycleA); | ||||
|             result.Should().ContainEquivalentOf(cycleB); | ||||
|             result.Should().ContainEquivalentOf(cycleC); | ||||
|             result.Should().ContainEquivalentOf(cycleD); | ||||
|             result.Should().ContainEquivalentOf(cycleE); | ||||
|             result.Should().HaveCount(5); | ||||
|         } | ||||
| 
 | ||||
|         [Test] | ||||
|         public void SimpleCyclesComplex() | ||||
|         { | ||||
|             var myGraph = new DirectedGraph<int>(); | ||||
|             myGraph.AddVertices(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); | ||||
|             myGraph.AddEdges( | ||||
|                 Tuple.Create(0, 1), | ||||
|                 Tuple.Create(1, 2), | ||||
|                 Tuple.Create(2, 3), | ||||
|                 Tuple.Create(3, 0), | ||||
|                 Tuple.Create(0, 3), | ||||
|                 Tuple.Create(3, 4), | ||||
|                 Tuple.Create(4, 5), | ||||
|                 Tuple.Create(5, 0), | ||||
|                 Tuple.Create(0, 1), | ||||
|                 Tuple.Create(1, 6), | ||||
|                 Tuple.Create(6, 7), | ||||
|                 Tuple.Create(7, 8), | ||||
|                 Tuple.Create(8, 0), | ||||
|                 Tuple.Create(8, 9) | ||||
|             ); | ||||
| 
 | ||||
|             var result = myGraph.SimpleCycles(); | ||||
|             var cycleA = new int[] { 0, 3 }; | ||||
|             var cycleB = new int[] { 0, 1, 2, 3, 4, 5 }; | ||||
|             var cycleC = new int[] { 0, 1, 2, 3 }; | ||||
|             var cycleD = new int[] { 0, 3, 4, 5 }; | ||||
|             var cycleE = new int[] { 0, 1, 6, 7, 8 }; | ||||
| 
 | ||||
|             result.Should().ContainEquivalentOf(cycleA); | ||||
|             result.Should().ContainEquivalentOf(cycleB); | ||||
|             result.Should().ContainEquivalentOf(cycleC); | ||||
|             result.Should().ContainEquivalentOf(cycleD); | ||||
|             result.Should().ContainEquivalentOf(cycleE); | ||||
|             result.Should().HaveCount(5); | ||||
|         } | ||||
| 
 | ||||
|         [Test] | ||||
|         public void Cyclic() | ||||
|         { | ||||
|             var myGraph = new DirectedGraph<int>(); | ||||
|             myGraph.AddVertices(1, 2, 3, 4); | ||||
|             myGraph.AddEdges( | ||||
|                 Tuple.Create(1, 2), | ||||
|                 Tuple.Create(2, 3), | ||||
|                 Tuple.Create(3, 1), | ||||
|                 Tuple.Create(3, 4) | ||||
|             ); | ||||
| 
 | ||||
|             Assert.That(myGraph.Cyclic(), Is.True); | ||||
|         } | ||||
| 
 | ||||
|         [Test] | ||||
|         public void Acyclic() | ||||
|         { | ||||
|             var myGraph = new DirectedGraph<int>(); | ||||
|             myGraph.AddVertices(1, 2, 3, 4); | ||||
|             myGraph.AddEdges( | ||||
|                 Tuple.Create(1, 2), | ||||
|                 Tuple.Create(2, 3), | ||||
|                 Tuple.Create(3, 4) | ||||
|             ); | ||||
| 
 | ||||
|             Assert.That(myGraph.Cyclic(), Is.False); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -462,13 +462,20 @@ namespace Tests | |||
|             { | ||||
|                 var worldBuilder = new WorldBuilder(); | ||||
| 
 | ||||
|                 worldBuilder.AddEngine(new AEngine()); | ||||
|                 worldBuilder.AddEngine(new BEngine()); | ||||
|                 worldBuilder.AddEngine(new CEngine()); | ||||
|                 worldBuilder.AddEngine(new DEngine()); | ||||
| 
 | ||||
|                 Assert.DoesNotThrow(() => worldBuilder.Build()); | ||||
| 
 | ||||
|                 worldBuilder = new WorldBuilder(); | ||||
| 
 | ||||
|                 var engineA = worldBuilder.AddEngine(new AEngine()); | ||||
|                 var engineB = worldBuilder.AddEngine(new BEngine()); | ||||
|                 var engineC = worldBuilder.AddEngine(new CEngine()); | ||||
|                 var engineD = worldBuilder.AddEngine(new DEngine()); | ||||
| 
 | ||||
|                 Assert.DoesNotThrow(() => worldBuilder.Build()); | ||||
| 
 | ||||
|                 var world = worldBuilder.Build(); | ||||
| 
 | ||||
|                 world.Update(0.01f); | ||||
|  | @ -495,7 +502,7 @@ namespace Tests | |||
|                 var worldBuilder = new WorldBuilder(); | ||||
|                 worldBuilder.AddEngine(new ReadMessageEngine()); | ||||
| 
 | ||||
|                 worldBuilder.SendMessageDelayed(new AMessage {}, 0.5); | ||||
|                 worldBuilder.SendMessageDelayed(new AMessage { }, 0.5); | ||||
| 
 | ||||
|                 var world = worldBuilder.Build(); | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue