/// <summary> /// Recursively compares all possible routes and finds the shorted /// possible distance /// </summary> private int ShortestDistanceToAll(VisitNode fromNode, IEnumerable <VisitNode> nodesToVisit, List <NodeRoute> availableRoutes, bool returnToOrigin) { int result = Int32.MaxValue; foreach (VisitNode n in nodesToVisit) { if (n == fromNode) { continue; } VisitNode[] subtract = new VisitNode[] { n }; var findRoute = from r in availableRoutes where r.FromNode == fromNode && r.ToNode == n select r; int distanceTravelled = findRoute.First().DistanceTravelled; if (nodesToVisit.Count() > 1) { distanceTravelled += ShortestDistanceToAll(n, nodesToVisit.Except(subtract), availableRoutes, returnToOrigin); } else { // Sabotage non-origin node scores if (returnToOrigin && !n.IsStartPosition) { return(10000); } } if (distanceTravelled < result) { result = distanceTravelled; } } return(result); }
public int DistanceBetween(VisitNode startNode, VisitNode endNode) { int consoleTop = Console.CursorTop; Tuple <int, int> start = new Tuple <int, int>(startNode.XPosition, startNode.YPosition); Tuple <int, int> goal = new Tuple <int, int>(endNode.XPosition, endNode.YPosition); List <string> closedSet = new List <string>(); // The set of currently discovered nodes still to be evaluated. // Initially, only the start node is known. List <string> openSet = new List <string>(); openSet.Add(HashTuple(start)); // For each node, which node it can most efficiently be reached from. // If a node can be reached from many nodes, cameFrom will eventually contain the // most efficient previous step. Dictionary <string, string> cameFrom = new Dictionary <string, string>(); // For each node, the cost of getting from the start node to that node. Dictionary <string, int> gScore = new Dictionary <string, int>(); // The cost of going from start to start is zero. gScore[HashTuple(start)] = 0; // For each node, the total cost of getting from the start node to the goal // by passing by that node. That value is partly known, partly heuristic. Dictionary <string, int> fScore = new Dictionary <string, int>(); // For the first node, that value is completely heuristic. fScore[HashTuple(start)] = EstimateMoveCost(start, goal); while (openSet.Count > 0) { // VisualizePuzzle(consoleTop, goal.Item1, goal.Item2, cameFrom); foreach (var open in openSet) { if (!fScore.ContainsKey(open)) { Console.WriteLine("Value (" + open + ") is in the open set but doesn't have a score"); } } var findBestScoreInOpenSet = from o in openSet join n in fScore on o equals n.Key select n; var current = ParseTupleHash(findBestScoreInOpenSet.OrderBy(o => o.Value).First().Key); if (HashTuple(current) == HashTuple(goal)) { return(reconstruct_path(cameFrom, HashTuple(current)).Count - 1); } openSet.Remove(HashTuple(current)); closedSet.Add(HashTuple(current)); List <Tuple <int, int> > neighbours = CalcNeighbours(current); foreach (var neighbour in neighbours) { // Ignore the neighbor which is already evaluated. if (closedSet.Contains(HashTuple(neighbour))) { continue; } // The distance from start to a neighbor int tentative_gScore = gScore[HashTuple(current)] + 1; // Discover a new node if (!openSet.Contains(HashTuple(neighbour))) { openSet.Add(HashTuple(neighbour)); } else // This is not a better path. if (tentative_gScore >= gScore[HashTuple(neighbour)]) { continue; } // This path is the best until now. Record it! cameFrom[HashTuple(neighbour)] = HashTuple(current); gScore[HashTuple(neighbour)] = tentative_gScore; fScore[HashTuple(neighbour)] = gScore[HashTuple(neighbour)] + EstimateMoveCost(neighbour, goal); } } return(-1); }