Hi guys, Have you use a pathfinding algorithm in your games? I have a graph with over 5000 waypoints (nodes). The cost between two nodes is the last time taken by a car to drive from these nodes, so this cost is updated all time. For now I am using a dijsktra algorithm but it seems to be expensive (14 seconds), do you know any optimisation method or another algorithm?
Maybe switch to A* instead of Dijsktra? It's exactly the same thing but uses heuristics to speed it up. But running a Dijsktra on 5000 nodes should be faster.. My game map is a grid of 1 048 576 nodes and it takes about 2 seconds at most to get a path from the furthest points apart.
Well it'd be hard to say how many seconds it should take considering that it depends on the performance of the system you're running it on. But yeah, dijkstra should faster technically... assuming you're on a mid-range contemporary computer. What does your code for dijkstra look like? With that said though... I'd still upgrade to A*. It's nearly the same algorithm, just with heuristics added. This way it checks for routes to the goal since it tries to pick a route that heuristically is closer before it tests those farther. This means A* on average should solve quicker unless you just happen to be on a map that always has you needing to backtrack/move away from the goal, to get to the goal.
Code (CSharp): public static List<Waypoint> Dijsktra(Waypoint start, Waypoint end) { // We don't accept null arguments if (start == null || end == null) return null; // The final path List<Waypoint> path = new List<Waypoint>(); // If the start and end are same node, we can return the start node if (start == end) { path.Add(start); return path; } // The list of unvisited nodes List<Waypoint> unvisited = new List<Waypoint>(); // Previous nodes in optimal path from source Dictionary<Waypoint, Waypoint> previous = new Dictionary<Waypoint, Waypoint>(); // The calculated distances, set all to Infinity at start, except the start Node Dictionary<Waypoint, float> distances = new Dictionary<Waypoint, float>(); for (int i = 0; i < Graph.Count; i++) { Waypoint node; node = Graph[i]; unvisited.Add(node); // Setting the node distance to Infinity distances.Add(node, float.MaxValue); } // Set the starting Node distance to zero distances[start] = 0f; while (unvisited.Count != 0) { // Ordering the unvisited list by distance, smallest distance at start and largest at end unvisited = unvisited.OrderBy(node => distances[node]).ToList(); // Getting the Node with smallest distance Waypoint current = unvisited[0]; // Remove the current node from unvisisted list unvisited.Remove(current); // When the current node is equal to the end node, then we can break and return the path if (current == end) { // Construct the shortest path while (previous.ContainsKey(current)) { // Insert the node onto the final result path.Insert(0, current); // Traverse from start to end current = previous[current]; } // Insert the source onto the final result path.Insert(0, current); break; } // Looping through the Node connections (neighbors) and where the connection (neighbor) is available at unvisited list for (int i = 0; i < current.Nodes.Count; i++) { Waypoint neighbor = current.Nodes[i].Waypoint; // Getting the distance between the current node and the connection (neighbor) float length = current.Nodes[i].Distance; // The distance from start node to this connection (neighbor) of current node float fullLength = distances[current] + length; // A shorter path to the connection (neighbor) has been found if (fullLength < distances[neighbor]) { distances[neighbor] = fullLength; previous[neighbor] = current; } } } return path; }
So for starters I can see some major memory over-usage in your implementation. You create lists willy nilly. You even create a new list every time you sort 'unvisited' instead of sorting the existing list in place. This is very costly not just on the GC, but because every time you create a list the code has to iterate the existing collection and fill said new list. So that 'OrderBy' is doing the large number of operations to order that list, but then tacking on the iteration of filling the new list. There are other optimizations I would suggest. Like using a BinaryHeap instead of a list for the unvisited collection, which does shorter sorts on entry of items. But implementing a BinaryHeap at this point is probably a bit much when just reducing all that list creation would probably save you a bunch. To give you an example here are my Dijkstra and A* implementations: Dijkstra: https://github.com/lordofduct/space.../SPPathfinding/Graphs/DijkstraPathResolver.cs A*: https://github.com/lordofduct/space...ter/SPPathfinding/Graphs/AStarPathResolver.cs