public void ClearAdjacencyGraph_InvalidatesOldNodes()
        {
            var solver = new PathSolver <Point, PathTestOption>(_testMap);

            // Build a graph based on all three points.
            solver.BuildAdjacencyGraph(new Point[] { _startPt, _reachableEndPt, _unreachableEndPt });

            // Clear the graph, and then rebuild it with just one point.
            solver.ClearAdjacencyGraph();
            solver.BuildAdjacencyGraph(_startPt);

            // Try to find a path to _unreachableEndPt.  PathSolver should complain that it doesn't know about that point.
            PathResult <Point> pathResult = null;

            Assert.ThrowsException <PathfindingException>(() => pathResult = solver.FindPath(_startPt, _unreachableEndPt, PathTestOption.Normal));
        }
Exemple #2
0
        static void Main(string[] args)
        {
            // Create the map we'll use for this program.  Since StarMap implements IPathGraph, it can answer
            // questions PathSolver asks about connections and distances between stars.
            var maxJumpDist = _shipTypes.Select((ship) => ship.MaxJumpDistance).Max();
            var starMap     = CreateMap(maxJumpDist);

            // Create a PathSolver instance that we'll use.  The first type parameter, string, is what
            // we'll use to identify nodes in the graph.  The second, ShipCharacteristics, is the type of
            // caller data that we will pass to FindPath, and it will subsequently pass to Cost and EstimatedCost.
            // In this example, what type of spaceship we're plotting a path for.
            var solver = new PathSolver <string, ShipCharacteristics>(starMap);

            // Pre-build PathSolver's internal data.  We have to give it one or more seed points - nodes that
            // we know exist.  One is sufficient as long as all of the others are reachable from it.
            solver.BuildAdjacencyGraph("A");

            // Show the user the star map.
            foreach (var row in _asciiMap)
            {
                Console.WriteLine(row);
            }

            // Prompt for input about what paths to plot.
            string startStar;
            string endStar;

            Console.Write("Enter starting star: ");
            var startStarInput = Console.ReadLine();

            if (startStarInput.Length > 0)
            {
                startStar = startStarInput.ToUpper().Substring(0, 1);
            }
            else
            {
                return;
            }

            Console.Write("Enter destination star: ");
            var endStarInput = Console.ReadLine();

            if (endStarInput.Length > 0)
            {
                endStar = endStarInput.ToUpper().Substring(0, 1);
            }
            else
            {
                return;
            }

            // Find a path for each type of spaceship, and display it to the user.
            Console.WriteLine($"--{startStar} to {endStar}--");
            foreach (var ship in _shipTypes)
            {
                WritePath(starMap, solver, startStar, endStar, ship);
            }
        }
        public void FindPath_ThrowsIfEmptyDestinationList()
        {
            var solver = new PathSolver <Point, PathTestOption>(_testMap);

            solver.BuildAdjacencyGraph(_startPt);
            PathResult <Point> pathResult = null;
            var destList = new List <Point>();

            Assert.ThrowsException <PathfindingException>(() => pathResult = solver.FindPath(_startPt, destList, PathTestOption.Normal));
        }
        public void FindPath_ThrowsIfDestNodeNotInGraph()
        {
            var solver = new PathSolver <Point, PathTestOption>(_testMap);

            solver.BuildAdjacencyGraph(_startPt);
            PathResult <Point> pathResult = null;
            var ptOutsideOfGraph          = new Point(-1, -1);

            Assert.ThrowsException <PathfindingException>(() => pathResult = solver.FindPath(_startPt, ptOutsideOfGraph, PathTestOption.Normal));
        }
        public void FindPath_NoPathToUnreachable()
        {
            // In this case, _startPt and _unreachableEndPt are disconnected in the adjacency graph.
            var solver = new PathSolver <Point, PathTestOption>(_testMap);

            solver.BuildAdjacencyGraph(new Point[] { _startPt, _reachableEndPt, _unreachableEndPt });
            var solution = solver.FindPath(_startPt, _unreachableEndPt, PathTestOption.Normal);

            Assert.IsTrue(solution.PathCost == double.PositiveInfinity);
            Assert.IsNull(solution.Path);
            StringAssert.Contains(solution.PerformanceSummary(), "Path not found");
        }
        public void FindPath_ZeroLengthPathToSelf()
        {
            var solver = new PathSolver <Point, PathTestOption>(_testMap);

            solver.BuildAdjacencyGraph(new Point[] { _startPt, _reachableEndPt, _unreachableEndPt });
            var solution = solver.FindPath(_startPt, _startPt, PathTestOption.Normal);

            Assert.IsTrue(solution.PathCost == 0);
            Assert.IsNotNull(solution.Path);
            Assert.IsTrue(solution.Path.Count == 0);
            StringAssert.Contains(solution.PerformanceSummary(), "Zero-length path");
        }
        public void PerformanceSummary_HasInfo()
        {
            var solver = new PathSolver <Point, PathTestOption>(_testMap);

            solver.BuildAdjacencyGraph(new Point[] { _startPt, _reachableEndPt, _unreachableEndPt });
            var solution = solver.FindPath(_startPt, _reachableEndPt, PathTestOption.Normal);

            var summary = solver.PerformanceSummary();

            Assert.IsNotNull(summary);
            StringAssert.Contains(summary, "pathCount=1;");
        }
        public void FindPath_NoPathIfAllInfiniteCosts()
        {
            // In this case, the start and end points are connected in the adjacency graph, but all possible paths
            // have an infinite cost.  PathSolver treats that as unreachable.
            var solver = new PathSolver <Point, PathTestOption>(_testMap);

            solver.BuildAdjacencyGraph(new Point[] { _startPt, _reachableEndPt, _unreachableEndPt });
            var solution = solver.FindPath(_startPt, _reachableEndPt, PathTestOption.InfiniteCost);

            Assert.IsTrue(solution.PathCost == double.PositiveInfinity);
            Assert.IsNull(solution.Path);
            StringAssert.Contains(solution.PerformanceSummary(), "Path not found");
        }
        public void FindPath_GoodPathToReachable()
        {
            var solver = new PathSolver <Point, PathTestOption>(_testMap);

            solver.BuildAdjacencyGraph(new Point[] { _startPt, _reachableEndPt, _unreachableEndPt });
            var solution = solver.FindPath(_startPt, _reachableEndPt, PathTestOption.Normal);

            Assert.IsTrue(solution.PathCost >= _testMap.EstimatedCost(_startPt, _reachableEndPt, PathTestOption.Normal));
            Assert.IsNotNull(solution.Path);
            Assert.IsTrue(solution.Path.Count > 0);
            Assert.IsTrue(solution.Path[solution.Path.Count - 1] == _reachableEndPt);
            Assert.IsFalse(solution.Path.Contains(_startPt));
            Assert.IsTrue(solution.NodesReprocessedCount == 0);
            StringAssert.Contains(solution.PerformanceSummary(), $"Path from {_startPt}");
        }
        public void FindPath_GoodPathEvenWithOverestimate()
        {
            // If we give PathSolver a bad estimate, we should still get a path, but it won't always be optimal.
            // NodesReprocessedCount can only be > 0 in this case.
            var solver = new PathSolver <Point, PathTestOption>(_testMap);

            solver.BuildAdjacencyGraph(new Point[] { _startPt, _reachableEndPt, _unreachableEndPt });
            var solution = solver.FindPath(_startPt, _reachableEndPt, PathTestOption.OverEstimateRemainingDistance);

            Assert.IsNotNull(solution.Path);
            Assert.IsTrue(solution.Path.Count > 0);
            Assert.IsTrue(solution.Path[solution.Path.Count - 1] == _reachableEndPt);
            Assert.IsFalse(solution.Path.Contains(_startPt));
            Assert.IsTrue(solution.NodesReprocessedCount > 0);
            StringAssert.Contains(solution.PerformanceSummary(), $"Path from {_startPt}");
        }
Exemple #11
0
        private static void Demo()
        {
            // Create a tile map.  In this case we're doing it from hard-coded strings, but it
            // would be trivial to get it from a file instead.
            var map = new Map(_demoMapStrings);

            // Create an instace of an IPathGraph.  This is a class that the caller provides
            // that answers which tiles are adjacent to which, and what the cost is to move from
            // one to the next.
            var tileGraph = new TileGraph(map);

            // Create a PathSolver instance.  The first type parameter here is Point2D.  It's whatever
            // we're using to identify nodes (tile in this case).  The second one - int here - is a dummy
            // type since we don't care about callerData/passthrough values in this example.
            var solver = new PathSolver <Point2D, int>(tileGraph);

            var allImportantPoints = _demoGoalPts.Concat(_demoStartPts);

            // Pre-build the PathSolver's data structures.  We're telling it to build a graph of all of the points
            // reachable from the ones we give it here.
            solver.BuildAdjacencyGraph(allImportantPoints);

            // Create a path and draw the map for each point in _demoStartPts.
            foreach (var startPt in _demoStartPts)
            {
                // Find the shortest path from startPt to any of points listed in _interestingGoals.  Of course,
                // you could just give it one ending point.  The third parameter, 0 here, is unused in this example.
                var pathResult = solver.FindPath(startPt, _demoGoalPts, 0);

                // Write the map out as a grid characters, with a couple extra bits:
                //   O is the starting point for our path.
                //   X is one of the ending points for our path.
                //   . is a tile we moved through on the path.
                var startPtsArray = new Point2D[] { startPt };
                var mapStrings    = map.RowStrings(pathResult.Path, startPtsArray, _demoGoalPts);

                Console.WriteLine();
                foreach (var mapRow in mapStrings)
                {
                    Console.WriteLine(mapRow);
                }

                // Write performance info.
                Console.WriteLine(pathResult.PerformanceSummary());
            }
        }
Exemple #12
0
        /// <summary>
        /// Search for a whole lot of paths using a large map.
        /// </summary>
        private static void Benchmark()
        {
            // Build the necessary pieces (as above in Demo()).
            var map       = new Map(_benchmarkMapStrings);
            var tileGraph = new TileGraph(map);
            var solver    = new PathSolver <Point2D, int>(tileGraph);

            // Init the solver's graph.  (This step is included in solver.LifetimeSolutionTimeMS, by the way.)
            solver.BuildAdjacencyGraph(_benchmarkPts);

            // Solve a path for every combination of 1 starting point and 2 destination points.  (So if P is the number of
            // points, then we're solving P*(P-1)*(P-2)/2 paths.)
            for (var startIdx = 0; startIdx < _benchmarkPts.Length; ++startIdx)
            {
                var startPt = _benchmarkPts[startIdx];
                for (var endIdx1 = 0; endIdx1 < _benchmarkPts.Length; ++endIdx1)
                {
                    if (endIdx1 == startIdx)
                    {
                        continue;
                    }

                    for (var endIdx2 = endIdx1 + 1; endIdx2 < _benchmarkPts.Length; ++endIdx2)
                    {
                        if (endIdx2 == startIdx)
                        {
                            continue;
                        }

                        var endPts     = new[] { _benchmarkPts[endIdx1], _benchmarkPts[endIdx2] };
                        var pathResult = solver.FindPath(startPt, endPts, 0);
                    }
                }
            }

            // Write out a summary of the PathSolver's lifetime statistics.
            Console.WriteLine(solver.PerformanceSummary());
        }