directed weighted graph
							parent
							
								
									d6f2e0b793
								
							
						
					
					
						commit
						df320194f1
					
				| 
						 | 
					@ -0,0 +1,169 @@
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using MoreLinq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace MoonTools.Core.Graph
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class DirectedWeightedGraph<TNode, TEdgeData> : IGraph<TNode, TEdgeData> where TNode : System.IEquatable<TNode>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        protected HashSet<TNode> nodes = new HashSet<TNode>();
 | 
				
			||||||
 | 
					        protected Dictionary<TNode, HashSet<TNode>> neighbors = new Dictionary<TNode, HashSet<TNode>>();
 | 
				
			||||||
 | 
					        protected Dictionary<(TNode, TNode), TEdgeData> edgeToEdgeData = new Dictionary<(TNode, TNode), TEdgeData>();
 | 
				
			||||||
 | 
					        protected Dictionary<(TNode, TNode), int> weights = new Dictionary<(TNode, TNode), int>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // store search sets to prevent GC
 | 
				
			||||||
 | 
					        protected HashSet<TNode> openSet = new HashSet<TNode>();
 | 
				
			||||||
 | 
					        protected HashSet<TNode> closedSet = new HashSet<TNode>();
 | 
				
			||||||
 | 
					        protected Dictionary<TNode, int> gScore = new Dictionary<TNode, int>();
 | 
				
			||||||
 | 
					        protected Dictionary<TNode, int> fScore = new Dictionary<TNode, int>();
 | 
				
			||||||
 | 
					        protected Dictionary<TNode, TNode> cameFrom = new Dictionary<TNode, TNode>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public IEnumerable<TNode> Nodes => nodes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public void AddNode(TNode node)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (Exists(node)) { return; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            nodes.Add(node);
 | 
				
			||||||
 | 
					            neighbors[node] = new HashSet<TNode>();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public void AddNodes(params TNode[] nodes)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            foreach (var node in nodes)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                AddNode(node);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void CheckNodes(params TNode[] givenNodes)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            foreach (var node in givenNodes)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (!Exists(node))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    throw new ArgumentException($"Vertex {node} does not exist in the graph");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public void AddEdge(TNode v, TNode u, int weight, TEdgeData data)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            CheckNodes(v, u);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (Exists(v, u)) { throw new ArgumentException($"Edge with vertex {v} and {u} already exists in the graph"); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            neighbors[v].Add(u);
 | 
				
			||||||
 | 
					            weights.Add((v, u), weight);
 | 
				
			||||||
 | 
					            edgeToEdgeData.Add((v, u), data);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public void AddEdges(params (TNode, TNode, int, TEdgeData)[] edges)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            foreach (var edge in edges)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                AddEdge(edge.Item1, edge.Item2, edge.Item3, edge.Item4);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public void Clear()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            nodes.Clear();
 | 
				
			||||||
 | 
					            neighbors.Clear();
 | 
				
			||||||
 | 
					            edgeToEdgeData.Clear();
 | 
				
			||||||
 | 
					            weights.Clear();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public bool Exists(TNode node) => nodes.Contains(node);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public bool Exists(TNode v, TNode u)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            CheckNodes(v, u);
 | 
				
			||||||
 | 
					            return neighbors[v].Contains(u);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public IEnumerable<TNode> Neighbors(TNode node)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            CheckNodes(node);
 | 
				
			||||||
 | 
					            return neighbors[node];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void CheckEdge(TNode v, TNode u)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            CheckNodes(v, u);
 | 
				
			||||||
 | 
					            if (!Exists(v, u)) { throw new ArgumentException($"Edge between vertex {v} and vertex {u} does not exist in the graph"); }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public int Weight(TNode v, TNode u)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            CheckEdge(v, u);
 | 
				
			||||||
 | 
					            return weights[(v, u)];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public TEdgeData EdgeData(TNode v, TNode u)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            CheckEdge(v, u);
 | 
				
			||||||
 | 
					            return edgeToEdgeData[(v, u)];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private IEnumerable<(TNode, TNode)> ReconstructPath(Dictionary<TNode, TNode> cameFrom, TNode currentNode)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            while (cameFrom.ContainsKey(currentNode))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var edge = (cameFrom[currentNode], currentNode);
 | 
				
			||||||
 | 
					                currentNode = edge.Item1;
 | 
				
			||||||
 | 
					                yield return edge;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public IEnumerable<(TNode, TNode)> AStarShortestPath(TNode start, TNode end, Func<TNode, TNode, int> heuristic)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            CheckNodes(start, end);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            openSet.Clear();
 | 
				
			||||||
 | 
					            closedSet.Clear();
 | 
				
			||||||
 | 
					            gScore.Clear();
 | 
				
			||||||
 | 
					            fScore.Clear();
 | 
				
			||||||
 | 
					            cameFrom.Clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            openSet.Add(start);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            gScore[start] = 0;
 | 
				
			||||||
 | 
					            fScore[start] = heuristic(start, end);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            while (openSet.Count > 0)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var currentNode = openSet.MinBy(node => fScore[node]).First();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (currentNode.Equals(end))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    return ReconstructPath(cameFrom, currentNode).Reverse();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                openSet.Remove(currentNode);
 | 
				
			||||||
 | 
					                closedSet.Add(currentNode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                foreach (var neighbor in Neighbors(currentNode))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    if (!closedSet.Contains(neighbor))
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        var weight = weights[(currentNode, neighbor)];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        var tentativeGScore = gScore.ContainsKey(currentNode) ? gScore[currentNode] + weight : int.MaxValue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if (!openSet.Contains(neighbor) || tentativeGScore < gScore[neighbor])
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            cameFrom[neighbor] = currentNode;
 | 
				
			||||||
 | 
					                            gScore[neighbor] = tentativeGScore;
 | 
				
			||||||
 | 
					                            fScore[neighbor] = tentativeGScore + heuristic(neighbor, end);
 | 
				
			||||||
 | 
					                            openSet.Add(neighbor);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return Enumerable.Empty<(TNode, TNode)>();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -25,7 +25,10 @@ namespace MoonTools.Core.Graph
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public void AddNode(TNode node)
 | 
					        public void AddNode(TNode node)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            if (Exists(node)) { return; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            nodes.Add(node);
 | 
					            nodes.Add(node);
 | 
				
			||||||
 | 
					            neighbors[node] = new HashSet<TNode>();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public void AddNodes(params TNode[] nodes)
 | 
					        public void AddNodes(params TNode[] nodes)
 | 
				
			||||||
| 
						 | 
					@ -38,13 +41,9 @@ namespace MoonTools.Core.Graph
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public void AddEdge(TNode v, TNode u, int weight, TEdgeData data)
 | 
					        public void AddEdge(TNode v, TNode u, int weight, TEdgeData data)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (Exists(v) && Exists(u))
 | 
					            CheckNodes(v, u);
 | 
				
			||||||
            {
 | 
					
 | 
				
			||||||
            var id = Guid.NewGuid();
 | 
					            var id = Guid.NewGuid();
 | 
				
			||||||
                if (!neighbors.ContainsKey(v))
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    neighbors[v] = new HashSet<TNode>();
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            neighbors[v].Add(u);
 | 
					            neighbors[v].Add(u);
 | 
				
			||||||
            weights.Add(id, weight);
 | 
					            weights.Add(id, weight);
 | 
				
			||||||
            if (!edges.ContainsKey((v, u)))
 | 
					            if (!edges.ContainsKey((v, u)))
 | 
				
			||||||
| 
						 | 
					@ -55,15 +54,6 @@ namespace MoonTools.Core.Graph
 | 
				
			||||||
            edgeToEdgeData.Add(id, data);
 | 
					            edgeToEdgeData.Add(id, data);
 | 
				
			||||||
            IDToEdge.Add(id, (v, u));
 | 
					            IDToEdge.Add(id, (v, u));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
            else if (!Exists(v))
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                throw new InvalidVertexException("Vertex {0} does not exist in the graph", v);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                throw new InvalidVertexException("Vertex {0} does not exist in the graph", u);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public void AddEdges(params (TNode, TNode, int, TEdgeData)[] edges)
 | 
					        public void AddEdges(params (TNode, TNode, int, TEdgeData)[] edges)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
| 
						 | 
					@ -78,6 +68,8 @@ namespace MoonTools.Core.Graph
 | 
				
			||||||
            nodes.Clear();
 | 
					            nodes.Clear();
 | 
				
			||||||
            neighbors.Clear();
 | 
					            neighbors.Clear();
 | 
				
			||||||
            weights.Clear();
 | 
					            weights.Clear();
 | 
				
			||||||
 | 
					            edges.Clear();
 | 
				
			||||||
 | 
					            IDToEdge.Clear();
 | 
				
			||||||
            edgeToEdgeData.Clear();
 | 
					            edgeToEdgeData.Clear();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -98,10 +90,7 @@ namespace MoonTools.Core.Graph
 | 
				
			||||||
            return edges.ContainsKey((v, u)) ? edges[(v, u)] : Enumerable.Empty<Guid>();
 | 
					            return edges.ContainsKey((v, u)) ? edges[(v, u)] : Enumerable.Empty<Guid>();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public bool Exists(TNode node)
 | 
					        public bool Exists(TNode node) => nodes.Contains(node);
 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return nodes.Contains(node);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public bool Exists(TNode v, TNode u)
 | 
					        public bool Exists(TNode v, TNode u)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,224 @@
 | 
				
			||||||
 | 
					using NUnit.Framework;
 | 
				
			||||||
 | 
					using FluentAssertions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using MoonTools.Core.Graph;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Tests
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class DirectedWeightedGraphTests
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        EdgeData dummyEdgeData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Test]
 | 
				
			||||||
 | 
					        public void AddNode()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var myGraph = new DirectedWeightedGraph<int, EdgeData>();
 | 
				
			||||||
 | 
					            myGraph.AddNode(4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            myGraph.Exists(4).Should().BeTrue();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Test]
 | 
				
			||||||
 | 
					        public void AddNodes()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var myGraph = new DirectedWeightedGraph<int, EdgeData>();
 | 
				
			||||||
 | 
					            myGraph.AddNodes(4, 20, 69);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            myGraph.Exists(4).Should().BeTrue();
 | 
				
			||||||
 | 
					            myGraph.Exists(20).Should().BeTrue();
 | 
				
			||||||
 | 
					            myGraph.Exists(69).Should().BeTrue();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Test]
 | 
				
			||||||
 | 
					        public void AddEdge()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var myGraph = new DirectedWeightedGraph<int, EdgeData>();
 | 
				
			||||||
 | 
					            myGraph.AddNodes(5, 6);
 | 
				
			||||||
 | 
					            myGraph.AddEdge(5, 6, 10, dummyEdgeData);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            myGraph.Neighbors(5).Should().Contain(6);
 | 
				
			||||||
 | 
					            myGraph.Weight(5, 6).Should().Be(10);
 | 
				
			||||||
 | 
					            myGraph.EdgeData(5, 6).Should().Be(dummyEdgeData);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            myGraph.Invoking(x => x.AddEdge(5, 6, 3, dummyEdgeData)).Should().Throw<ArgumentException>();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Test]
 | 
				
			||||||
 | 
					        public void AddEdges()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var a = new NumEdgeData { testNum = 1 };
 | 
				
			||||||
 | 
					            var b = new NumEdgeData { testNum = 2 };
 | 
				
			||||||
 | 
					            var c = new NumEdgeData { testNum = 3 };
 | 
				
			||||||
 | 
					            var d = new NumEdgeData { testNum = 4 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var myGraph = new DirectedWeightedGraph<int, NumEdgeData>();
 | 
				
			||||||
 | 
					            myGraph.AddNodes(1, 2, 3, 4);
 | 
				
			||||||
 | 
					            myGraph.AddEdges(
 | 
				
			||||||
 | 
					                (1, 2, 5, a),
 | 
				
			||||||
 | 
					                (2, 3, 6, b),
 | 
				
			||||||
 | 
					                (2, 4, 7, c),
 | 
				
			||||||
 | 
					                (3, 4, 8, d)
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            myGraph.Neighbors(1).Should().Contain(2);
 | 
				
			||||||
 | 
					            myGraph.Neighbors(2).Should().Contain(3);
 | 
				
			||||||
 | 
					            myGraph.Neighbors(2).Should().Contain(4);
 | 
				
			||||||
 | 
					            myGraph.Neighbors(3).Should().Contain(4);
 | 
				
			||||||
 | 
					            myGraph.Neighbors(1).Should().NotContain(4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            myGraph.Weight(1, 2).Should().Be(5);
 | 
				
			||||||
 | 
					            myGraph.Weight(2, 3).Should().Be(6);
 | 
				
			||||||
 | 
					            myGraph.Weight(2, 4).Should().Be(7);
 | 
				
			||||||
 | 
					            myGraph.Weight(3, 4).Should().Be(8);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            myGraph.EdgeData(1, 2).Should().Be(a);
 | 
				
			||||||
 | 
					            myGraph.EdgeData(2, 3).Should().Be(b);
 | 
				
			||||||
 | 
					            myGraph.EdgeData(2, 4).Should().Be(c);
 | 
				
			||||||
 | 
					            myGraph.EdgeData(3, 4).Should().Be(d);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            myGraph.Invoking(x => x.AddEdge(2, 4, 9, d)).Should().Throw<ArgumentException>();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Test]
 | 
				
			||||||
 | 
					        public void Clear()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var myGraph = new DirectedWeightedGraph<int, EdgeData>();
 | 
				
			||||||
 | 
					            myGraph.AddNodes(1, 2, 3, 4);
 | 
				
			||||||
 | 
					            myGraph.AddEdges(
 | 
				
			||||||
 | 
					                (1, 2, 5, dummyEdgeData),
 | 
				
			||||||
 | 
					                (2, 3, 6, dummyEdgeData),
 | 
				
			||||||
 | 
					                (2, 4, 7, dummyEdgeData)
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            myGraph.Clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            myGraph.Nodes.Should().BeEmpty();
 | 
				
			||||||
 | 
					            myGraph.Invoking(x => x.Neighbors(1)).Should().Throw<ArgumentException>();
 | 
				
			||||||
 | 
					            myGraph.Invoking(x => x.Weight(1, 2)).Should().Throw<ArgumentException>();
 | 
				
			||||||
 | 
					            myGraph.Invoking(x => x.EdgeData(1, 2)).Should().Throw<ArgumentException>();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Test]
 | 
				
			||||||
 | 
					        public void NodeExists()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var myGraph = new DirectedWeightedGraph<int, EdgeData>();
 | 
				
			||||||
 | 
					            myGraph.AddNodes(1, 2, 3);
 | 
				
			||||||
 | 
					            myGraph.AddEdges(
 | 
				
			||||||
 | 
					                (1, 2, 4, dummyEdgeData),
 | 
				
			||||||
 | 
					                (2, 3, 5, dummyEdgeData)
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            myGraph.Exists(1).Should().BeTrue();
 | 
				
			||||||
 | 
					            myGraph.Exists(2).Should().BeTrue();
 | 
				
			||||||
 | 
					            myGraph.Exists(3).Should().BeTrue();
 | 
				
			||||||
 | 
					            myGraph.Exists(4).Should().BeFalse();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Test]
 | 
				
			||||||
 | 
					        public void EdgeExists()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var myGraph = new DirectedWeightedGraph<int, EdgeData>();
 | 
				
			||||||
 | 
					            myGraph.AddNodes(1, 2, 3);
 | 
				
			||||||
 | 
					            myGraph.AddEdges(
 | 
				
			||||||
 | 
					                (1, 2, 4, dummyEdgeData),
 | 
				
			||||||
 | 
					                (2, 3, 5, dummyEdgeData)
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            myGraph.Exists(1, 2).Should().BeTrue();
 | 
				
			||||||
 | 
					            myGraph.Exists(2, 3).Should().BeTrue();
 | 
				
			||||||
 | 
					            myGraph.Exists(1, 3).Should().BeFalse();
 | 
				
			||||||
 | 
					            myGraph.Invoking(x => x.Exists(3, 4)).Should().Throw<ArgumentException>();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Test]
 | 
				
			||||||
 | 
					        public void Neighbors()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var myGraph = new DirectedWeightedGraph<int, EdgeData>();
 | 
				
			||||||
 | 
					            myGraph.AddNodes(1, 2, 3);
 | 
				
			||||||
 | 
					            myGraph.AddEdges(
 | 
				
			||||||
 | 
					                (1, 2, 4, dummyEdgeData),
 | 
				
			||||||
 | 
					                (2, 3, 5, dummyEdgeData)
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            myGraph.Neighbors(1).Should().Contain(2);
 | 
				
			||||||
 | 
					            myGraph.Neighbors(2).Should().Contain(3);
 | 
				
			||||||
 | 
					            myGraph.Neighbors(1).Should().NotContain(3);
 | 
				
			||||||
 | 
					            myGraph.Invoking(x => x.Neighbors(4)).Should().Throw<System.ArgumentException>();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Test]
 | 
				
			||||||
 | 
					        public void Weight()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var myGraph = new DirectedWeightedGraph<int, EdgeData>();
 | 
				
			||||||
 | 
					            myGraph.AddNodes(1, 2, 3);
 | 
				
			||||||
 | 
					            myGraph.AddEdges(
 | 
				
			||||||
 | 
					                (1, 2, 4, dummyEdgeData),
 | 
				
			||||||
 | 
					                (2, 3, 5, dummyEdgeData)
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            myGraph.Weight(1, 2).Should().Be(4);
 | 
				
			||||||
 | 
					            myGraph.Weight(2, 3).Should().Be(5);
 | 
				
			||||||
 | 
					            myGraph.Invoking(x => x.Weight(3, 4)).Should().Throw<System.ArgumentException>();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Test]
 | 
				
			||||||
 | 
					        public void EdgeData()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var a = new NumEdgeData { testNum = 3 };
 | 
				
			||||||
 | 
					            var b = new NumEdgeData { testNum = 5 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var myGraph = new DirectedWeightedGraph<int, NumEdgeData>();
 | 
				
			||||||
 | 
					            myGraph.AddNodes(1, 2, 3);
 | 
				
			||||||
 | 
					            myGraph.AddEdges(
 | 
				
			||||||
 | 
					                (1, 2, 4, a),
 | 
				
			||||||
 | 
					                (2, 3, 5, b)
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            myGraph.EdgeData(1, 2).Should().Be(a);
 | 
				
			||||||
 | 
					            myGraph.EdgeData(2, 3).Should().Be(b);
 | 
				
			||||||
 | 
					            myGraph.Invoking(x => x.EdgeData(2, 4)).Should().Throw<ArgumentException>();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Test]
 | 
				
			||||||
 | 
					        public void AStarShortestPath()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            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<char, MoveTypeEdgeData>();
 | 
				
			||||||
 | 
					            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
 | 
				
			||||||
 | 
					                .AStarShortestPath('a', 'h', (x, y) => 1)
 | 
				
			||||||
 | 
					                .Select(edge => myGraph.EdgeData(edge.Item1, edge.Item2))
 | 
				
			||||||
 | 
					                .Should()
 | 
				
			||||||
 | 
					                .ContainInOrder(
 | 
				
			||||||
 | 
					                    run, jump, wallJump
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					                .And
 | 
				
			||||||
 | 
					                .HaveCount(3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            myGraph.Invoking(x => x.AStarShortestPath('a', 'z', (x, y) => 15)).Should().Throw<System.ArgumentException>();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -239,7 +239,7 @@ namespace Tests
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            myGraph
 | 
					            myGraph
 | 
				
			||||||
                .AStarShortestPath('a', 'h', (x, y) => 15)
 | 
					                .AStarShortestPath('a', 'h', (x, y) => 1)
 | 
				
			||||||
                .Select(id => myGraph.EdgeData(id))
 | 
					                .Select(id => myGraph.EdgeData(id))
 | 
				
			||||||
                .Should()
 | 
					                .Should()
 | 
				
			||||||
                .ContainInOrder(
 | 
					                .ContainInOrder(
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue