🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

shortest path algorithm

Started by
34 comments, last by bpj1138 22 years, 9 months ago
Given a system of nodes linked together, you want to find the shortest path from node a to node b. Since there are many paths and you search through them recursively this immediately seems like the traveling salesman problem, but it''s not. The traveling salesman problem doesn''t have a destination node, and that''s why it''s unbound. The best way to even walk the path would be to have a "least distance to destination" measurement in each node, so you can easily select the next node in the path, as in:

class Node extends Vector { 

  Point position;                           // x,y,z of this node
  double leastDistanceToDestination;        // least distance to destination

  Node nextNode() {
     Enumeration e = elements();            // get list of links 
     Node nextNode = e.nextElement();       // init next node to first link 
     while (e.hasMoreElements()) {          // for each link from this node 
         Node n = e.nextElement();
         // set next node to n if n''s least distance is lesser 
         if (n.leastDistanceToDestination < nextNode.leastDistanceToDestination) 
             nextNode = n; 
     } 
     return nextNode;
  }
}
 
To walk the path, the controlling program just repeatedly calls: currentNode = currentNode.nextNode(); Which automaticly selects the shortest path. Of course we still don''t know what these "least distances" are. The algorithm to compute the least distance measurements: The algorithm starts by setting all the leastDistanceToDestination to finite Infinity (maximum double floating point value). You can do this simply by

  void resetDistances() { 
     if (leastDistanceToDestination < Double.MAX_VALUE) { 
           leastDistanceToDestination = Double.MAX_VALUE; 
           // recursively call all the links 
           for (Enumeration e = elements(); e.hasMoreElements(); ) { 
              Node n = e.nextElement(); 
              n.resetDistances(); 
           } 
     } 
  } 
 
Then, appropriately, the destination node''s leastDistanceToDestination value is set to 0. The algorithm then recursively examines the nodes linked to the current node, starting with the destination node. If the current node''s least destination distance plus the absolute distance to the linked node is less than what''s in the linked node''s leastDistanceToDestination variable, then the algorithm updates that node''s least distance value to the newly computed value, and only then makes the recursive call on that node. It''s easy to see that initially, since all the nodes are set to finite infinity, and the destination node''s leastDistanceToDestination is 0, each node linked to the destination will be "updated", because 0 + "real distance to linked node" < finite infinity. The program would then update these nodes'' values to whatever the 0 + "real distance to linked node" and recursively call those nodes to update the distances. This is just like resetting the distances, except you do some additional calculating.
 
  void measureDistances() { 
     for (Enumeration e = elements(); e.hasMoreElements(); ) { 
              Node n = e.nextElement(); 
              double computedDistance = this.leastDistanceToDestination +  
                        (Math.sqrt((this.position - n.position)^2)); 
              if (computedDistance < n.leastDistanceToDestination) { 
                   n.leastDistanceToDestination = computedDistance; 
                   n.measureDistances();
              } 
     } 
  } 
 
So, finally, the controlling program would have to do several steps to find the shortest path between two nodes.. First call "resetDistances" then "measureDistances", and finally walk the path using "nextNode" method. I hope this works for your game, I have found it pretty useful. One final note is that the algorithm is not thread safe, unless the nodes are cloned.
--bart
Advertisement
Perhaps I''m mis-reading your post but what you have described is simply depth first search (DFS).

Cheers,

Timkin
well, of course, it''s still a recursive algorithm. the difference is, if you just traverse the nodes, without computing the distance variables, the search will take eons..

if you go and look up "depth first search", you probably won''t find the optimizing "least distance" huristic there..

thanks for your message nonetheless, it''s a valid question.

--bart
It might be helpful to look up the A* algorithm.


Mike
"Unintentional death of one civilian by the US is a tragedy; intentional slaughter of a million by Saddam - a statistic." - Unknown
Yeah, except A* still doesn''t describe the huristic.
--bart
I think I need to explain the algorithm further, and mention why it differs from other algorithms, since there is so much interest in that.

My algorithm progressively updates each node''s "distance to destination" variable. The first recursive pass from the destination node to the first link from that node fills the stucture with "wrong distances", because they''re all relative to the first link taken. Successive recurisve calls on the remaining links "update" the distance variables progressively.
The algorithm then converges on the solution mathematicly.

Once the solution is found, whatever entity is wishing to reach the destination node simply selects a link with the least distance variable.

So you can see, there are actual two passes, one just computes distance, the other selects the path. The path isn''t generated explicitly.

I hope this answers your questions.

--bart

--bart
(I''m trying to keep my messages low bandwidth)

I think it''s hilarious the responses I get about this algorithm..

1) does it even work?
2) it must be A*
3) trivial
4) depth first search (that was a new one)
5) __________ (what will it be next?)

I don''t think people even know what A* is. A* is not even an algorithm. Not a complete one, anyway. It just says that instead of doing a full recursive search, you can use various huristics to narrow the search, A* doesn''t define the huristic. You can use A* in chess for example, instead of trying each solution, you can rule out some, and "not take those branches". For example, in chess, you can move the side pawns first, but you don''t really wanna take that branch, you always move the middle pawn. So that would be a huristic of the first branch in chess.

So let''s see, it turns out all the comments are right, it is depth first, but narrowed down, and the solution is trivial because computing distance between two points is trivial.

But is it trivial?

Oh yes, and it does work, btw..

--bart
Sounds like a step further from my old 'AIGraph' idea which (upon looking at it more) I realize is just a way to have A* skip nodes that do not give the algorithm a change in direction.

So as I understand it, your algorithm uses DFS to walk down the nodes marking down all the distances, then, it goes down a second time finding the shortest distance? Then, you save the shortest path between each node so you don't have to calculate it again right?

What if your graph has 1000 nodes? Thats a lot of paths to save!

A heuristic function should be able to help you select the best node to continue the search so that you dont have to go through the 'bad' nodes. A heuristic isn't defined by A* because different problems require different heuristics. You wouldn't want to use the same heuristic you use for chess to play checkers would you?

Invader X
Invader's Realm

Edited by - Invader X on September 11, 2001 1:02:49 AM
Actually, I happen to know A* pretty well. It''s basically a derivative of A* using a fairly trivial huerstic. Oh well, glad I could provide some humor, even if I don''t get what''s funny. Thanks for the code.


Mike
"Unintentional death of one civilian by the US is a tragedy; intentional slaughter of a million by Saddam - a statistic." - Unknown
Ok, I''m glad we''re on the same page now.

Like I mentioned in the document, the algorithm is not thread safe. This means that once an entity is walking the path, it effectively locks that entire structure. So you have to clone it for each entity.

Btw, the code is pseudo-java.. the trivial distance calculation isn''t implemented...

--bart

This topic is closed to new replies.

Advertisement