<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Fabulous Adventures In Coding : AStar</title><link>http://blogs.msdn.com/ericlippert/archive/tags/AStar/default.aspx</link><description>Tags: AStar</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Path Finding Using A* in C# 3.0, Part Four</title><link>http://blogs.msdn.com/ericlippert/archive/2007/10/10/path-finding-using-a-in-c-3-0-part-four.aspx</link><pubDate>Wed, 10 Oct 2007 17:17:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:5250978</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>11</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/5250978.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=5250978</wfw:commentRss><description>&lt;DIV class=mine&gt;
&lt;P&gt;Finally we are ready to translate our pseudocode into C# 3.0.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;What do we need to make the algorithm run?&amp;nbsp;We need a start node, a destination node, a function which tells us the exact distance between two neighbours, and a function which tells us the estimated distance between the last node on a proposed path and the destination node. &lt;/P&gt;
&lt;P&gt;We also need the ability to take any node and get a list of its neighbours. We'll represent that by an interface:&lt;/P&gt;&lt;SPAN class=code&gt;
&lt;P mce_keep="true"&gt;interface IHasNeighbours&amp;lt;N&amp;gt;&amp;nbsp; &lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; IEnumerable&amp;lt;N&amp;gt; Neighbours { get; }&lt;BR&gt;}&lt;/SPAN&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;Recall that the pseudocode looked like this:&lt;/P&gt;&lt;SPAN class=code&gt;
&lt;P mce_keep="true"&gt;closed = {}&lt;BR minmax_bound="true"&gt;q = emptyqueue;&lt;BR minmax_bound="true"&gt;q.enqueue(0.0, makepath(start))&lt;BR minmax_bound="true"&gt;while q is not empty&lt;BR minmax_bound="true"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; p = q.dequeueCheapest&lt;BR minmax_bound="true"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if closed contains p.last then continue;&lt;BR minmax_bound="true"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if p.last == destination then return p&lt;BR minmax_bound="true"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; closed.add(p.last)&lt;BR minmax_bound="true"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; foreach n in p.last.neighbours&amp;nbsp;&lt;BR minmax_bound="true"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; newpath = p.continuepath(n)&lt;BR minmax_bound="true"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; q.enqueue(newpath.TotalCost + estimateCost(n, destination), newpath)&lt;BR minmax_bound="true"&gt;return null&lt;/P&gt;&lt;/SPAN&gt;
&lt;P&gt;And now we're all set. The translation from pseudocode to real code is quite straightforward:&lt;/P&gt;&lt;SPAN class=code&gt;
&lt;P mce_keep="true"&gt;static public Path&amp;lt;Node&amp;gt; FindPath&amp;lt;Node&amp;gt;(&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Node start, &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Node destination, &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Func&amp;lt;Node, Node, double&amp;gt; distance, &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Func&amp;lt;Node, double&amp;gt; estimate)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; where Node : IHasNeighbours&amp;lt;Node&amp;gt;&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; var closed = new HashSet&amp;lt;Node&amp;gt;();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; var queue = new PriorityQueue&amp;lt;double, Path&amp;lt;Node&amp;gt;&amp;gt;();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; queue.Enqueue(0, new Path&amp;lt;Node&amp;gt;(start));&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; while (!queue.IsEmpty)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var path = queue.Dequeue();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if&amp;nbsp;(closed.Contains(path.LastStep))&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; continue;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (path.LastStep.Equals(destination))&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return path;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; closed.Add(path.LastStep);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; foreach(Node n in path.LastStep.Neighbours)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; double d = distance(path.LastStep, n);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var newPath = path.AddStep(n, d);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; queue.Enqueue(newPath.TotalCost + estimate(n), newPath);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return null;&lt;BR&gt;}&lt;/P&gt;&lt;/SPAN&gt;
&lt;P mce_keep="true"&gt;You might wonder why we check to see if the current-best-path ends in a "closed" node after the dequeue,&amp;nbsp;rather than testing that before we do the enqueue. Think about it this way: suppose we take the best path off the queue,&amp;nbsp;note that&amp;nbsp;its end&amp;nbsp;node is "closed" so that we don't come back to it, and put all of its extensions on the queue. There might be a number of other paths which end in that node presently on the queue. All of them must be, by definition, worse than the&amp;nbsp;path we just took off the priority queue. We should therefore not even consider them as possbilities anymore. If we happen to put more paths with that property on the queue, that's unfortunate. But when we eventually get to them we'll discard them automatically so its not a big deal.&lt;/P&gt;
&lt;P mce_keep="true"&gt;A nice property of the A* algorithm is that it finds the optimal path in a reasonable amount of time provided that:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;the estimating function never overestimates the distance to the goal. (Think about what happens if the estimating function sometimes overestimates the distance; if the optimal path is one of the ones overestimated then it will possibly not make it to the front of the priority queue before a nonoptimal solution is found.)&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;calling the estimating function does not take very long.&lt;/LI&gt;&lt;/UL&gt;
&lt;P mce_keep="true"&gt;One way to ensure that the estimating function never overestimates the distance is to always estimate zero. If you do so then this becomes Dijkstra's algorithm. However, the better your estimating function can get without going over (this really should have been called the "The Price Is Right" algorithm...) the faster this will identify the truly optimal path.&lt;/P&gt;
&lt;P mce_keep="true"&gt;Unfortunately, the space complexity of this algorithm can be really quite high on complicated graphs. There are more complex versions of this algorithm which can deal with the space complexity, but I'm not going to go there.&lt;/P&gt;
&lt;P mce_keep="true"&gt;I have a nice example of using A* to find the shortest path around a lake (but not the &lt;A class="" href="http://blogs.msdn.com/ericlippert/archive/2004/12/15/whidbey-island-and-bagel-mathematics.aspx" mce_href="http://blogs.msdn.com/ericlippert/archive/2004/12/15/whidbey-island-and-bagel-mathematics.aspx"&gt;longest shortest path&lt;/A&gt;!) but I'm not going to post it here until Orcas ships. I'll just put up the whole project file at that time and you can check it out all at once.&lt;/P&gt;
&lt;P mce_keep="true"&gt;Next time: at long last, Eric talks about variance in C#.&lt;/P&gt;&lt;/DIV&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=5250978" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Rarefied+Heights/default.aspx">Rarefied Heights</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/AStar/default.aspx">AStar</category></item><item><title>Path Finding Using A* in C# 3.0, Part Three</title><link>http://blogs.msdn.com/ericlippert/archive/2007/10/08/path-finding-using-a-in-c-3-0-part-three.aspx</link><pubDate>Mon, 08 Oct 2007 17:03:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:5250741</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>14</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/5250741.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=5250741</wfw:commentRss><description>&lt;DIV class=mine&gt;
&lt;P&gt;In order to make the A* algorithm work we need to get the lowest-estimated-cost-path-discovered-so-far out of the list of paths under consideration. The standard data structure for doing so is called a “priority queue”. Priority queues are so-called because they are typically used to store a list of jobs where each job has an associated priority. &lt;/P&gt;
&lt;P&gt;Now, there’s a bit of a semantic problem with priority queues in that we typically think of “priority 1” as being &lt;EM&gt;higher&lt;/EM&gt; priority than “priority 2”, even though 1 is a &lt;EM&gt;smaller&lt;/EM&gt; number than 2. Fortunately for us, that is &lt;EM&gt;exactly&lt;/EM&gt; what we want in this case; the “highest priority” path is the one with the &lt;EM&gt;least&lt;/EM&gt; estimated cost. &lt;/P&gt;
&lt;P&gt;There are lots of ways to implement priority queues – I have a nice example of an immutable priority queue that I’ll probably blog about at some point, but for now, let’s go with an old-fashioned mutable priority queue.&lt;/P&gt;
&lt;P&gt;A priority queue can be implemented as list of sub-queues with the list sorted in priority order. The implementation is pretty straightforward:&lt;/P&gt;&lt;SPAN class=code&gt;
&lt;P&gt;class PriorityQueue&amp;lt;P, V&amp;gt;&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private SortedDictionary&amp;lt;P, Queue&amp;lt;V&amp;gt;&amp;gt; list = new SortedDictionary&amp;lt;P, Queue&amp;lt;V&amp;gt;&amp;gt;();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void Enqueue(P priority, V value)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Queue&amp;lt;V&amp;gt; q;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (!list.TryGetValue(priority, out q))&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; q = new Queue&amp;lt;V&amp;gt;();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; list.Add(priority, q);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; q.Enqueue(value);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public V Dequeue()&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // will throw if there isn’t any first element!&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var pair = list.First();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var v = pair.Value.Dequeue();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (pair.Value.Count == 0) // nothing left of the top priority.&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; list.Remove(pair.Key);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return v;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public bool IsEmpty&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; get { return !list.Any(); }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;}&lt;/P&gt;&lt;/SPAN&gt;
&lt;P&gt;We could implement &lt;SPAN class=code&gt;IEnumerable&amp;lt;V&amp;gt;&lt;/SPAN&gt;, a &lt;SPAN class=code&gt;Peek&lt;/SPAN&gt; operation, etc, but this is all we need for A*, so let’s not go crazy here.&lt;/P&gt;
&lt;P&gt;Next time: now we have all the parts we need to implement A*, so let's do it already.&lt;BR&gt;&lt;/P&gt;&lt;/DIV&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=5250741" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Rarefied+Heights/default.aspx">Rarefied Heights</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/AStar/default.aspx">AStar</category></item><item><title>Path Finding Using A* in C# 3.0, Part Two</title><link>http://blogs.msdn.com/ericlippert/archive/2007/10/04/path-finding-using-a-in-c-3-0-part-two.aspx</link><pubDate>Thu, 04 Oct 2007 17:33:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:5250440</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>25</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/5250440.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=5250440</wfw:commentRss><description>&lt;DIV class=mine&gt;
&lt;P&gt;In order to &lt;A class="" href="http://blogs.msdn.com/ericlippert/archive/2007/10/02/path-finding-using-a-in-c-3-0.aspx" mce_href="http://blogs.msdn.com/ericlippert/archive/2007/10/02/path-finding-using-a-in-c-3-0.aspx"&gt;implement the A* algorithm in C# 3.0&lt;/A&gt; I am going to need to implement some custom data structures. Today we’ll consider how to implement the “path”.&lt;/P&gt;
&lt;P&gt;You’ll notice in my description of the algorithm that the only operations we perform on paths are:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Make a new path consisting of a single node.&lt;/LI&gt;
&lt;LI&gt;Make a new path by adding a new node onto the end of an existing path.&lt;/LI&gt;
&lt;LI&gt;Fetch the last element on the path.&lt;/LI&gt;
&lt;LI&gt;Get the total cost of a path.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;This cries out to me “Eric! A path is an immutable stack!” &lt;/P&gt;
&lt;P&gt;A mutable stack like &lt;SPAN class=code&gt;System.Collections.Generic.Stack&amp;lt;T&amp;gt;&lt;/SPAN&gt; is clearly not suitable. We want to be able to take an existing path and create new paths from it for all of the neighbours of its last element, but &lt;STRONG&gt;pushing a new node onto the standard stack modifies the stack&lt;/STRONG&gt;. We’d have to make copies of the stack before pushing it, which is silly because then we’d be duplicating all of its contents unnecessarily.&lt;/P&gt;
&lt;P&gt;Immutable stacks do not have this problem. Pushing onto an immutable stack merely creates a brand-new stack which links to the old one as its tail. Since the stack is immutable, there is no danger of some other code coming along and messing with the tail contents. You can keep on using the old stack to your heart’s content.&lt;/P&gt;
&lt;P&gt;ASIDE: &lt;STRONG&gt;Immutable data structures are the way of the future in C#. &lt;/STRONG&gt;It is much easier to reason about a data structure if you know that it will never change. Since they cannot be modified, they are automatically threadsafe. Since they cannot be modified, you can maintain a stack of past “snapshots” of the structure, and suddenly undo-redo implementations become trivial. On the down side, they do tend to chew up memory, but hey, that’s what garbage collection was invented for, so don’t sweat it. I’ll be talking more about programming using immutable data structures in this space over the next few months.&lt;/P&gt;
&lt;P&gt;Let’s make an immutable stack of nodes which tracks the total cost of the whole path. Later on, we’ll see that we need to enumerate the nodes of this thing, so we’ll do a trivial implementation of &lt;SPAN class=code&gt;IEnumerable&lt;/SPAN&gt; while we’re at it. And since we don’t know exactly what a node will look like, let’s make the thing generic:&lt;/P&gt;&lt;SPAN class=code&gt;
&lt;P&gt;class Path&amp;lt;Node&amp;gt; : IEnumerable&amp;lt;Node&amp;gt;&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public Node LastStep { get; private set; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public Path&amp;lt;Node&amp;gt; PreviousSteps { get; private set; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public double TotalCost { get; private set; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private Path(Node lastStep, Path&amp;lt;Node&amp;gt; previousSteps, double totalCost)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; LastStep = lastStep;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; PreviousSteps = previousSteps;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; TotalCost = totalCost;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public Path(Node start) : this(start, null, 0) {}&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public Path&amp;lt;Node&amp;gt; AddStep(Node step, double stepCost)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return new Path&amp;lt;Node&amp;gt;(step, this, TotalCost + stepCost);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public IEnumerator&amp;lt;Node&amp;gt; GetEnumerator()&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; for (Path&amp;lt;Node&amp;gt; p = this; p != null; p = p.PreviousSteps)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; yield return p.LastStep;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; IEnumerator IEnumerable.GetEnumerator()&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return this.GetEnumerator();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;}&lt;/P&gt;&lt;/SPAN&gt;
&lt;P&gt;Well, that was painless. Next time: implementing the priority queue.&lt;/P&gt;&lt;/DIV&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=5250440" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Rarefied+Heights/default.aspx">Rarefied Heights</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/AStar/default.aspx">AStar</category></item><item><title>Path Finding Using A* in C# 3.0, Part One</title><link>http://blogs.msdn.com/ericlippert/archive/2007/10/02/path-finding-using-a-in-c-3-0.aspx</link><pubDate>Wed, 03 Oct 2007 02:31:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:5249654</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>8</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/5249654.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=5249654</wfw:commentRss><description>&lt;DIV class=mine&gt;
&lt;P&gt;As we get into the home stretch for the Orcas release I’ve been spending a little time lately just playing around implementing some “classic” algorithms and data structures in C#. The one I implemented today is the famous A* algorithm. &lt;/P&gt;
&lt;P&gt;Surely you’ve played games like Age of Empires. You know the kind of games I mean. There are a bunch of little dudes walking around a map containing barriers (mountains, walls, etc) and somehow the game’s pseudo-intelligence finds the shortest possible path for the guys to walk from point A to point B. Most games do this with a surprisingly straightforward algorithm.&lt;/P&gt;
&lt;P&gt;Suppose you’ve got a bunch of “nodes”. Say, intersections in a city. Each node has a bunch of “neighbours” – intersections that can be immediately reached by locomoting down a particular street involved in the intersection. Each “edge” (ie, street) between nodes has a “cost” – the amount of time it takes to travel from one node to the neighbour on that street. Perhaps the cost is based on its length, traffic density, etc.&lt;/P&gt;
&lt;P&gt;A “path from A to B” consists of a list of nodes starting with A, ending with B, where every step along the path is from neighbour to neighbour. The total cost of a path is obviously the sum of all the costs of every transition from neighbour to neighbour on the path.&lt;/P&gt;
&lt;P&gt;Let’s start by considering a really stupid, awful, buggy path finding algorithm, and then we’ll make it better.&lt;/P&gt;&lt;SPAN class=code&gt;
&lt;P&gt;q = emptyqueue&lt;BR&gt;q.enqueue(makepath(start))&lt;BR&gt;while q is not empty&lt;BR&gt;&amp;nbsp; &amp;nbsp; p = q.dequeue&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if p.last == destination then return p&lt;BR&gt;&amp;nbsp; &amp;nbsp; foreach n in p.last.neighbours&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; q.enqueue(p.continuepath(n))&lt;BR&gt;// failed to find path.&lt;BR&gt;return null&lt;/P&gt;&lt;/SPAN&gt;
&lt;P&gt;What’s wrong with this picture?&lt;/P&gt;
&lt;P&gt;Well, suppose we have&amp;nbsp;four nodes,arranged like this: A &amp;lt;--&amp;gt; C &amp;lt;--&amp;gt; D &amp;lt;--&amp;gt; B. Does this algorithm find the obvious path from A to B?&lt;/P&gt;
&lt;P&gt;Run the code in your head: it starts by putting the path “A” on the queue. Then it takes it off and puts “A-C” on the queue. Then it takes it off and puts “A-C-A” and “A-C-D” on the queue. Then it takes “A-C-A” off the queue and puts “A-C-A-C” on the queue... OK, eventually we get there, but we seem to be spending a lot of time going in circles.&amp;nbsp; And if D does not actually connect to B, if you can't get there from here, then we really &lt;EM&gt;do&lt;/EM&gt; go into an infinite loop.&lt;/P&gt;
&lt;P&gt;Clearly this is all screwed up.&amp;nbsp; We need to disallow paths which loop back on themselves, because those are clearly not going to be the best possible path. We're at best&amp;nbsp;wasting time looking at them, and at worst going into an infinite loop that chews up all the memory in the system. &lt;/P&gt;
&lt;P&gt;Let’s fix that up. We’ll create a “closed” set, ie, the set of “nodes we have already considered, so do not loop back to them.”&lt;/P&gt;&lt;SPAN class=code&gt;
&lt;P&gt;closed = {}&lt;BR&gt;q = emptyqueue;&lt;BR&gt;q.enqueue(makepath(start))&lt;BR&gt;while q is not empty&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; p = q.dequeue&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if closed contains p.last then continue&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if p.last == destination then return p&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; closed.add(p.last)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; foreach n in p.last.neighbours&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; q.enqueue(p.continuepath(n))&lt;BR&gt;return null&lt;/P&gt;&lt;/SPAN&gt;
&lt;P&gt;This is &lt;EM&gt;better&lt;/EM&gt;, in that it actually terminates in a finite amount of time. But my goodness, is this algorithm ever slow. Essentially the algorithm is “At every intersection, check to see if you're at your destination. If not, pick a direction – any direction! - and walk as far as you can like that without revisiting your steps. If you ever run out of options, backtrack until you get to an intersection that goes somewhere you haven’t tried yet. Keep doing that until either you get to your destination or you have tried every possible intersection.”&lt;/P&gt;
&lt;P&gt;I guarantee you that if you try that in a reasonably sized city, you will not get from point A to point B in any kind of reasonable time. And when you do succeed, the path which you come up with may well be absolutely crazy. Obviously this is not how people navigate between points in cities. &lt;/P&gt;
&lt;P&gt;The problem is that we are picking which neighbour to try next essentially at random. We can do better than that. &lt;STRONG&gt;We want to direct our search so that the path we spend most of our time concentrating on is the path which is most likely to lead us to the goal.&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Now, that sounds like a bit of a chicken-and-egg problem. Finding the best path is precisely what we are trying to do, so how can we determine which path is the one we want to be concentrating on?&lt;/P&gt;
&lt;P&gt;We shall have to guess. We will rank all potential paths based on the sum of two factors: &lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;First, what is the total cost of each potential path so far? This is &lt;EM&gt;known&lt;/EM&gt;.&lt;/LI&gt;
&lt;LI&gt;Second, what is the estimated cost of getting from the end of each potential path to the goal? This is a &lt;EM&gt;guess&lt;/EM&gt;.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;And now our algorithm becomes:&lt;/P&gt;&lt;SPAN class=code&gt;
&lt;P&gt;closed = {}&lt;BR&gt;q = emptyqueue;&lt;BR&gt;q.enqueue(0.0, makepath(start))&lt;BR&gt;while q is not empty&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; p = q.dequeueCheapest&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if closed contains p.last then continue;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if p.last == destination then return p&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; closed.add(p.last)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; foreach n in p.last.neighbours&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; newpath = p.continuepath(n)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; q.enqueue(newpath.TotalCost + estimateCost(n, destination), newpath)&lt;BR&gt;return null&lt;/P&gt;&lt;/SPAN&gt;
&lt;P&gt;which is the famous A* algorithm! Surprisingly straightforward, eh?&lt;/P&gt;
&lt;P&gt;Next time: actually implementing this thing in C# 3.0.&lt;BR&gt;&lt;/P&gt;&lt;/DIV&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=5249654" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Rarefied+Heights/default.aspx">Rarefied Heights</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/AStar/default.aspx">AStar</category></item></channel></rss>