/// <summary>
        /// Calculates the shortest path through the submitted graph
        /// from the submitted start and end points. Throws exception
        /// if a path cannot be computed. The implementation uses the
        /// breadth-first search algorithm to traverse the graph.
        /// </summary>
        /// <param name="graph">Graph to traverse.</param>
        /// <param name="startPoint">Start point of path.</param>
        /// <param name="endPoint">End point of path.</param>
        /// <returns></returns>
        public Point[] CalculateLine(Node[][] graph, Point startPoint, Point endPoint)
        {
            Stopwatch timer = new Stopwatch(); // DEBUG code

            // Prepare the graph for searching.
            GraphTools<Node>.SearchReset(graph);

            // Queue that will hold the next nodes to be processed.
            Queue<Node> queue = new Queue<Node>();

            Node startNode = graph[startPoint.X][startPoint.Y];
            // Set the start node to be parent of itself to signify it as start point.
            startNode.Parent = graph[startPoint.X][startPoint.Y];
            // Set distance of start node to 0
            startNode.Distance = 0;
            // Enqueue the start point unless it is allready occupied.
            if (!startNode.Occupied)
                queue.Enqueue(graph[startPoint.X][startPoint.Y]);

            int count = 0; // DEBUG code
            timer.Start(); // DEBUG code
            while (queue.Count > 0)
            {
                count++;  // DEBUG code

                // Next node in the queue.
                Node current = queue.Dequeue();
                // If we found the end point end loop
                if (current.X == endPoint.X && current.Y == endPoint.Y)
                {
                    break;
                }

                // Get nodes adjacent to the node being processed.
                Node[] adjacent = GraphTools<Node>.GetAdjacentElements(graph, current);

                // For each adjacent node check that it's not occupied by another line
                // and it has not been visisted by a shorter path.
                foreach (Node node in adjacent)
                {
                    if (!node.Occupied && (current.Distance + GraphTools<Node>.Distance(current, node)) < node.Distance)
                    {
                        // Update the adjacent node and enqueue it.
                        node.Parent = current;
                        node.Distance = current.Distance + GraphTools<Node>.Distance(current, node);
                        queue.Enqueue(node);
                    }
                }
            }
            timer.Stop(); // DEBUG code
            Debug.Print(string.Format("Number of iterations for BFS: {0}, time: {1}ms", count, timer.ElapsedMilliseconds));  // DEBUG code

            // Use the helper function to find the computed path and return it.
            return GetPath(graph[endPoint.X][endPoint.Y]);
        }
        public void WhenComparingSmaller_ReturnsPostive()
        {
            //Prepare
            Node a = new Node { Distance = 2 };
            Node b = new Node { Distance = 1 };
            DistanceComparer<Node> target = new DistanceComparer<Node>();

            //Act
            int result = target.Compare(a, b);

            //Verify
            Assert.IsTrue(result > 0);
        }
        public void WhenComparingEqual_ReturnsZero()
        {
            //Prepare
            Node a = new Node { Distance = 1 };
            Node b = new Node { Distance = 1 };
            DistanceComparer<Node> target = new DistanceComparer<Node>();

            //Act
            int result = target.Compare(a, b);

            //Verify
            Assert.AreEqual(0, result);
        }
        public void WhenComparingSmaller_ReturnsPostive()
        {
            //Prepare
            Node a = new Node { Distance = 1, X = 1, Y = 1 };
            Node b = new Node { Distance = 1, X = 2, Y = 2 };
            Node c = new Node { Distance = 1, X = 1, Y = 1 };
            Node d = new Node { Distance = 2, X = 1, Y = 1 };

            Node goal = new Node { X = 5, Y = 5 };
            DirectedDistanceComparer<Node> target = new DirectedDistanceComparer<Node>(goal);

            //Act
            int result1 = target.Compare(a, b);
            int result2 = target.Compare(d, c);

            //Verify
            Assert.IsTrue(result1 > 0);
            Assert.IsTrue(result2 > 0);
        }
        public void WhenDistanceCalled_ReturnsDouble()
        {
            //Prepare
            Node a = new Node { X = 2, Y = 2 };
            Node b = new Node { X = 3, Y = 3 };
            Node c = new Node { X = 0, Y = 0 };
            Node d = new Node { X = 1, Y = 1 };
            Node e = new Node { X = 1, Y = 0 };

            //Act
            double result1 = GraphTools<Node>.Distance(a, b);
            double result2 = GraphTools<Node>.Distance(b, a);
            double result3 = GraphTools<Node>.Distance(c, d);
            double result4 = GraphTools<Node>.Distance(d, d);
            double result5 = GraphTools<Node>.Distance(d, e);

            //Verify
            Assert.AreEqual(Math.Sqrt(2), result1);
            Assert.AreEqual(Math.Sqrt(2), result2);
            Assert.AreEqual(Math.Sqrt(2), result3);
            Assert.AreEqual(0, result4);
            Assert.AreEqual(1, result5);
        }
        /// <summary>
        /// Calculates the shortest path through the submitted graph
        /// from the submitted start and end points. Throws exception
        /// if a path cannot be computed. The implementation uses
        /// the A* algorithm to find the shortest path.
        /// </summary>
        /// <param name="graph">Graph to traverse.</param>
        /// <param name="startPoint">Start point of path.</param>
        /// <param name="endPoint">End point of path.</param>
        /// <returns></returns>
        public Point[] CalculateLine(Node[][] graph, Point startPoint, Point endPoint)
        {
            bool found = false;

            Stopwatch timer = new Stopwatch(); // DEBUG code

            // This implementation requires the nodes to be PriorityQueueNodes.
            PriorityQueueNode[][] prioGraph = graph as PriorityQueueNode[][];

            // Prepare the nodes for searching
            GraphTools<Node>.SearchReset(graph);

            // Set distance to start point to 0
            PriorityQueueNode source = prioGraph[startPoint.X][startPoint.Y];
            source.Distance = 0;
            source.Handle = null;

            // Create a new priority queue and add the start node to it
            IPriorityQueue<PriorityQueueNode> queue = this.CreateQueue(graph, graph[endPoint.X][endPoint.Y]);
            queue.Add(ref source.Handle, source);

            int count = 0; //DEBUG code
            timer.Start(); // DEBUG code
            while(!queue.IsEmpty)
            {
                count++; // DEBUG code

                // Fetch node with least distance
                PriorityQueueNode u = queue.DeleteMin();

                // If we arrived at the end point break the loop
                if (u.X == endPoint.X && u.Y == endPoint.Y)
                {
                    found = true;
                    break;
                }

                // For each adjacent node
                PriorityQueueNode[] adjacent = GraphTools<PriorityQueueNode>.GetAdjacentElements(prioGraph, u);
                foreach (PriorityQueueNode v in adjacent)
                {
                    // That is not occupied
                    if(!v.Occupied)
                    {
                        // If dist[u] + dist[u][v] < dist[v] we found a shorter path to v.
                        double distance = u.Distance + GraphTools<Node>.Distance(u, v);
                        if(distance < v.Distance)
                        {
                            v.Distance = distance;
                            v.Parent = u;
                            // Add or replace the found node to the priority queue
                            PriorityQueueNode x;
                            if(v.Handle == null)
                                queue.Add(ref v.Handle, v);
                            else if (queue.Find(v.Handle, out x))
                                queue.Replace(v.Handle, v);
                            else
                                queue.Add(ref v.Handle, v);
                        }
                    }
                }
            }
            timer.Stop(); // DEBUG code
            Debug.Print(string.Format("Number of iterations for A*: {0}, time: {1}ms", count, timer.ElapsedMilliseconds));  // DEBUG code

            if (!found)
                throw new ApplicationException("Unable to find a path between points.");

            // Use the helper function to find the computed path and return it.
            return GetPath(graph[endPoint.X][endPoint.Y]);
        }
        /// <summary>
        /// Get the path from a traversed graph.
        /// </summary>
        /// <param name="endPoint">Point where path ends.</param>
        /// <returns>An array of <see cref="Point"/>.</returns>
        private Point[] GetPath(Node endPoint)
        {
            List<Point> path = new List<Point>();
            Node current = endPoint;

            // Add nodes to the path until we reach the nodes which has itself as parent
            // which signifies it is the start point.
            while (current.Parent != null)
            {
                path.Add(new Point { X = current.X, Y = current.Y });
                current = current.Parent;
            }

            // Add the last point
            path.Add(new Point { X = current.X, Y = current.Y });

            // Reverse the order since we began at the end point.
            path.Reverse();

            return path.ToArray();
        }
        /// <summary>
        /// Creates a new IPriorityQueue containing submitted
        /// Node elements.
        /// </summary>
        /// <param name="nodes">Elements to create queue with.</param>
        /// <param name="goal">The goal node</param>
        /// <returns>A IPriorityQueue containing sumbitted nodes.</returns>
        private IPriorityQueue<PriorityQueueNode> CreateQueue(Node[][] nodes, Node goal)
        {
            IntervalHeap<PriorityQueueNode> queue = new IntervalHeap<PriorityQueueNode>(PriorityQueueNode.SortByDirectedDistance(goal));
            foreach (Node[] subnodes in nodes)
                foreach (PriorityQueueNode node in subnodes)
                {
                    node.Handle = null;
                }

            return queue;
        }
Beispiel #9
0
 /// <summary>
 /// Get IComparer for sorting by the Distance property
 /// with a predefined goal node.
 /// </summary>
 /// <param name="goal">The goal node</param>
 /// <returns>A new instance of IComparer</returns>
 public static IComparer<Node> SortByDirectedDistance(Node goal)
 {
     return new DirectedDistanceComparer<Node>(goal);
 }
        public void WhenSearchResetCalled_ResetsNodes()
        {
            //Prepare
            Node parent = new Node();
            int height = 100;
            int width = 200;
            Node[][] result = GraphTools<Node>.CreateGraph(height, width);
            for (int i = 0; i < result.Length; i++)
                for (int j = 0; j < result[i].Length; j++)
                {
                    result[i][j].Parent = parent;
                    result[i][j].Distance = i+j;
                }

            //Before the Act phase check that values have indeed been set.
            for (int i = 0; i < result.Length; i++)
                for (int j = 0; j < result[i].Length; j++)
                {
                    Assert.IsInstanceOfType(result[i][j], typeof(Node));
                    Assert.IsFalse(result[i][j].Occupied);
                    Assert.IsNotNull(result[i][j].Parent);
                    Assert.AreEqual(i, result[i][j].X);
                    Assert.AreEqual(j, result[i][j].Y);
                    Assert.AreEqual(i + j, result[i][j].Distance);
                }

            //Act
            GraphTools<Node>.SearchReset(result);

            //Verify
            Assert.AreEqual(width, result.Length);
            Assert.AreEqual(height, result[0].Length);
            for (int i = 0; i < result.Length; i++)
                for (int j = 0; j < result[i].Length; j++)
                {
                    Assert.IsInstanceOfType(result[i][j], typeof(Node));
                    Assert.IsFalse(result[i][j].Occupied);
                    Assert.IsNull(result[i][j].Parent);
                    Assert.AreEqual(i, result[i][j].X);
                    Assert.AreEqual(j, result[i][j].Y);
                    Assert.AreEqual(int.MaxValue, result[i][j].Distance);
                }
        }