Click here to Skip to main content
Email Password   helpLost your password?

Sample Image - PathFinder.png

Introduction

Some time ago, I had to make a project to determine the shortest path inside a matrix. I thought to myself, "There's nothing better than path-finding for this." There is a huge amount of links and explanation about Path Finding, but didn't find a version written in C# that could meet my needs. So, I decided to make the A* implementation in C#. This code was really useful for me and I bet it can be useful for many other people, too. I won't explain the algorithm implementation too much because just typing "pathfinding algorithm A*" into Google brings up a lot of documents wherein you can find every single detail about it.

About the application

A* is a generic algorithm and there are no perfect parameters to be set. The algorithm has many things that can be set, so the best way to determine the appropriate parameters for your project is to test different combinations. As a note: usually a good A* implementation does not use a standard ArrayList or List for the open nodes. If a standard List is used, the algorithm will spend a huge amount of time searching for nodes in that list. Instead, a priority queue should be used. I borrow code from BenDi for the priority queue implementation. I changed it a little bit and I also changed the implementation to use generics instead of ArrayList, which makes it run faster. This project is really useful for two reasons.

  1. I followed the A* implementation and I tried to implement it to run with good performance, so the algorithm itself can be easily reused in any project.
  2. The front-end gives a full chance to experiment with many variables where you can really watch and learn how it works, changing the heuristic, formula or options to analyze what could be the best setting for your project.

The call in the source code that does the entire job is the following:

public List<PathFinderNode> FindPath(Point start, Point end, byte[,] grid);

This method takes as parameters a start point, end point and the grid. It will return the path as a list of nodes with the coordinates. I made this call on a separate thread, which gives the opportunity to keep the control of the application when PathFinder is working.

Algorithm settings

Speed

This is the rendering speed; reducing speed permits detailed examination of how the algorithm opens and closes the nodes in real-time.

Diagonals

This hint will tell the algorithm if it is allowed to process diagonals as a valid path. If this check box is not set, the algorithm will process just 4 directions instead of 8.

Heavy Diagonals

If this check box is set, the cost of the diagonals will be bigger; this will make the algorithm avoid using diagonals.

Punish Change Direction

If this check box is set, every time the algorithm changes direction it will have a small cost. The end result is that if the path is found it will be comparatively smooth without too many direction changes, thus looking more natural. The downside is that it will take more time because it must research for extra nodes.

Reopen Closed Nodes

If this is checked, the algorithm is allowed to reopen nodes that were already closed when the cost is less than the previous value. If reopen nodes is allowed it will produce a better and smoother path, but it will take more time.

Heuristic

This is a constant that will affect the estimated distance from the current position to the goal destination. A heuristic function is used to create an estimate of how long it will take to reach the goal state. The better the estimate, the shorter the found path.

Formula

This is the equation used to calculate the heuristic. Different formulas will give different results: some will be faster, others slower and the end may vary. The formula to be used depends strongly on the A* algorithm's use.

Use Tie Breaker

Sometimes when A* is finding the path, it will find many possible choices for the same cost and destination. The tie breaker setting tells the algorithm that when it has multiple choices to research, instead it should keep going. As it goes, the changing costs can be used in a second formula to determine the "best guess" to follow. Usually, this formula is incrementing the heuristic from the current position to the goal, multiplied by a constant factor.

Heuristic = Heuristic + Abs(CurrentX * GoalY - GoalX * CurrentY) * 0.001   

Search Limit

This is the maximum number of closed nodes to be researched before a "Path not found" message is returned. This is a useful parameter because sometimes the grid can be too big and we need to know a path only if the goal is near the current position. It is also useful if the process can't spend too much time calculating the path.

Grid Size

This parameter just affects the front-end. It can change the grid size, where reducing the grid size gives a chance to create a bigger test but will take longer to render.

Fast PathFinder

When unchecked, the implementation used is the algorithm as it usually appears in the books. When checked, it will use my own PathFinder implementation. It requires more memory, but it is about 300 to 1500 times faster depending on the map complexity. See the PathFinder Optimization section below for more details.

Show Progress

This permits observation of the algorithm as it operates in real-time. If this box is checked, the completion time will be the calculation time plus the rendering time.

Completed Time

This is the time that the algorithm took to calculate the path. To know the true value, uncheck "Show Progress."

Path finder optimization

After I implemented the original algorithm, I got frustrated because of the amount of time it took to resolve paths. This was especially the case for bigger grids and when there was no solution to the path. Basically, I noticed that the open and closing list were killing the algorithm. The first optimization was to replace the open list by a sorted list and the close list by a hashtable. This improved the calculation time, but was still not what I had hoped for. Later, I replaced the open list from a sorted list to a priority queue; it made a change but still not a big difference.

The big problem was that when the grid was big (1000x1000), the amount of open and closed nodes in the list was huge. Searching those lists took a long time, whatever method I used. At first, I thought to use classes to keep the node information, but that was going to make the garbage collection crazy between the nodes' memory allocation and releasing the memory of the nodes that were disposed of. Instead of using classes, I decided to use structures and reuse them in the code. I got more improvements from this, but still nothing close to what maybe StarCraft does to handle eight hundred units in real-time.

My current application is like a Visio application where I need to find a path between objects. The objects are not moving, so I didn't need a super-fast algorithm, but I needed something that could react in less than one second. I needed to find a way to get nodes from the open list in O(1) or closer to that. I thought the only way to get that was to not have an open list at all. That is when I thought of using a calculation grid. This calculation grid was going to store the nodes. Thus, if I knew the (X, Y) location then I could reach the node immediately O(1).

Because of this I could get rid of the close list; I could mark a closed node directly in the calculation grid. Also, since every node has a link to the parent node, I would not need a close list at all. However, I could not get rid of the open list because I needed to keep getting the nodes with less total cost (F), and the second grid didn't help with that. This time, I kept using the open list (priority queue), but it was just to push and to get the node with the lowest cost. Priority queues are excellent for that, no linear access at all.

The only cons were that the memory consumption was huge to keep a second grid. That is because every cell stored a node and every node was 32 bytes long. Basically for a map (1000x1000) I needed 32MB of RAM. Because I was now accessing the second grid by coordinates (X, Y), I didn't need those values in the node anymore. That reduced 8 bytes multiplied by 1,000,000. I therefore saved 8MB of ram. Every node had a link to the parent nodes and those were int (32 bits) because the grid can never be too big. Then I replaced them for ushort (16 bits) and that made me save another 2 bytes by node. This saved me another 2MB. I also realized that the heuristic (H) is calculated for every node on the fly and it is not used for the algorithm anymore. So, I removed this from the node structure, too. Heuristic was an int (4 bytes) and so I saved another 4MB. I also had minimum nodes of 13 bytes, but because of memory alignment they took 16 bytes at run-time. I had to set the struct to use memory alignment for every byte:

[StructLayout(LayoutKind.Sequential, Pack=1)]

Finally, I got my 13 bytes for every node. For that reason, when running the sample, you will see that running FastPathFinder takes 13MB of extra memory.

I have to admit that it took me a fair amount of time to make it work because of the complexity of the A* debugging. I got my satisfaction when it worked, though. I could not believe that I got a minimum of 300 times faster for simple grids and more than 1500 times faster for complex grids. Still, I was inserting and removing nodes from the priority queue, which meant memory work and garbage collection coming into play. So, I figured out a way around keeping the nodes inside the priority queue: Instead of pushing and popping the node, I pushed and popped the address where the node is in the calculation grid. That let me save memory and run faster. The way I was storing coordinates in the priority queue was translating an (X, Y) coordinate into a linear coordinate:

Location = Y * grid width + X;

The problem arising there was that I had to translate back and forth between a linear coordinate and a map coordinate. So, I changed my calculation grid from a fixed map array:

PathFinderNode[,] 

To a linear array:

PathFinderNode[]

That made the code a lot clearer because there was no translation between map and linear coordinates. I also added a constraint to the size of the grid. This constraint was that the map must be a power of 2 in width and height. Doing that allowed shifting and logical operations, which are much faster than mathematical operators. Where before it was:

LinearLocation = LocationY * Width + LocationX;
�
LocationY = LinearLocation / Width;
LocationX = LinearLocation � LocationY;

It now became:

LinearLocation = (LocationY << Log(Width, 2)) | LocationX;
�
LocationX = LinearLocation & Width;
LocationY = LinearLocation >> Log(Width, 2);

After all this, when the standard PathFinder algorithm resolved the path for the map HardToGet.astar in 131 seconds, the optimized PathFinder got the same result in 100 milliseconds. It was a 1300-times improvement. Another optimization was found in that if the current open node was already in the open list and the current node total cost was less than the store in the list, then the old node would be removed or replaced. Instead, I decided to leave the old open node in the open list and just add the new one. The old node would have a higher cost, so it would be processed later. However, when processed, this node would already be closed and so ignored. This is a lot faster than going to the open list and removing the old open node.

Another optimization arose from the fact that, between path finding calls, I had to clear the calculation grid. The calculation grid stores objects of type PathFinderNode and every object has a field Status. This field tells if the node is open, closed or neither. Status could be 0 = not processed, 1 = open or 2 = closed. Zeroing the grid usually took about 30 milliseconds for a 1024x1024 grid and that had to be done between path finding calls. To optimize it, instead of zeroing the grid what I do is change the values for the node status between calls. Then between calls, it increments the status value by 2. So in the first path finding search, we have:

In the second path finding search we have:

And so on�

In this way, between path finding calls, it doesn't need to clear the calculation grid. It just uses different values for open and closed nodes; any other value means it's not researched. Another small optimization was to promote all local variables to member variables. This allows creation of all variables in the heap at once instead of creating/destroying them in the stack for every pathfinder call. I changed my cost (G) and total cost (F) from int to float in order to obtain more detailed calculations of the total cost. The path produced for complex maps was 99% similar to when int was used for the cost and total cost. I noticed, however, that even when the float calculation time didn't vary too much from int, the number of nodes re-evaluated was huge. This was because the nodes were keeping the decimal values where before they made the algorithm skip the node. Now they were re-evaluated, which made the algorithm perform roughly 10 times slower. The difference was not appreciable, so for that reason I kept using int and discarding the decimals on the cost calculation.

In the optimization journey, I basically got rid of almost all memory allocation and sequential searches for fixed allocations and minimum search. It was analogous to replacing all mobile parts in a machine with fixed ones. Still, there are more optimizations that can be done and I'll probably keep working on those. If you have some feedback about the optimization or what can be done to improve it, feel free to add a comment and I'll reply as soon as I can.

Toolbar

The toolbar allows to us to load, create new and save test scenarios. It also allows to insert nodes (obstacles) in the grid with different costs. By default, all nodes in the grid have a cost of "1," but this can be changed to another cost. The "X" in the toolbar is cost "0" and represents an impassable node. The "start" and "end" buttons let us put the start and end positions inside the grid before running the algorithm. The costs of the nodes are not limited to the costs defined in the toolbar. The mouse buttons can change the current cost of the nodes, too. While moving the mouse and pressing the:

Left Button --> The current node is set to the cost specified by the active cost button in the toolbar.

Right Button --> The current node cost is incremented with the cost specified by the active cost button in the toolbar

Left & Right Buttons --> The current node cost is decremented with the cost specified by the active button in the toolbar.

Front-end

When I did the A* implementation, I took a long time to find the best parameters for my real project. Because of that, I decided to create a front-end independently from the real application to help me find those values. The only reason for the front-end was testing and debugging, so the front-end currently has a poor design. There is a lot of things that can be done to make it better and run with better performance, but the objective of this article is to learn about A* implementation and not GDI optimization. For that reason, I did not spend too much time on it.

Some time ago, I saw a pretty cool application that implements A*, but I can't remember the name. It was in made in Delphi, but no source code was available. I took the main idea from there to create this front-end. I didn't want to make a clone of that application; rather, I thought it looked really interesting and that it could be nice to create something similar. There is a different namespace where it contains just the algorithm and the helper classes, the "Algorithms" namespace.

As a note, the rendering in real-time of the researching nodes is not persistent. Basically, the nodes are drawn directly in the window HDC (Device Context). Therefore if a portion of the window is invalidated, it won't be redraw again. If you move another window over the front-end, the current path will disappear. That can be resolved using a second grid and keeping the status of every node, but again, when I did the front-end it was just to debug the algorithm and see how the settings affect the path search.

You will probably notice that setting the speed to maximum (minimum value) still doesn't look like good performance. That's not because of the algorithm; that's because the algorithm is doing a lot of callbacks (events) to the front-end to allow the rendering. The first line inside PathFinder.cs is a #define:

#define DEBUGON

If this symbol is defined, then the algorithm will evaluate if the debugging events are defined. If they are, the algorithm will make a callback (event) for every step. When the application is used on a real project, it is strongly recommended that you remove that symbol from PathFinder.cs. Removing the symbol will hugely increase the performance of the algorithm. If the symbol is not defined, then the algorithm won't make any callback and will return just after it has found a path or a path was not found at all.

Conclusion

This application and code can help the beginner to the advance developer in exploring the A* algorithm step by step. Feel free to make any comments or recommendations.

History

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
QuestionDiagonal path through barriers
shekky
5:39 10 Nov '09  
if i had a few blocks that where positioned diagonally, the path would go through them like so:

x = wall
. = path


xxxxxxxxxxxxxxxxxxxxxxx
. x
. x
. x........
....x
x
x
xxxxxxxxxxxxxxxxxxxx



seems like those walls should black the path
GeneralHelp needed in modifying the algo.
vCracker
3:40 15 Apr '09  
Hi,

I have a problem while utilizing your pathfinder algo. Here is the detail of the same: http://silverlight.net/forums/t/89180.aspx

I'm developing a game in Silverlight which need path finder algo. I though it won't be a good idea to build of my own. So I give a search and found your A*. Its just perfect and Quite fast then other algos(A*) implementation. But I ran into a problem.

My requirement is something like this: This is a Tower defender game. So user can place defenders (similar to the wall) in a fashion similar to the image's wall(in forum). So ideally there should be no way from that diagonal. But for rest of the application there must be diagonal way(if possible). So how I modify your class to not include diagonals which are occupied in this fashion. (Sorry I can't be so expressive as I want to.)


-Vinit
QuestionWSN
mazfaiz
23:09 17 Nov '07  
is there anyone who hav implemented A* in Wireless Sensor Network?
Maybe is quite not familiar, but if we ignored the cost of transmission and energy it would be good...
i have try it but is so complicated to deploy random node in a field and placing some target node..
plz help me..

jho

GeneralWrong Grid Bounds
XChronos
19:18 3 Oct '07  
When you asking if a child node is out of the grid, you ask [X|Y] >= grid[X|Y] and that value is calculated with GetUpperBound which for my surprise gets the last index you can access, not the lenght!

For example:
int[] aaa = new int[10];
Console.WriteLine(aaa.GetUpperBound(0));

output: "9"

So, instead of using ">=" you must use ">" or you will be discarding an inner node.

I figure out when the end node was at the edge.
Questioncan i get some help?
c13l
23:19 26 Sep '07  
hi
i know here is not the best place to post this question.
but i wonder if anyone can help..

i need code to implement minimum spanning tree.
it doesn't matter what algorithm it is used as long as its a MST.
i've search this forum and find nothing.
most of the code i found at other places are written on C++ or pascal.
i have zero experience dealing with both language.
i expected something thats written on VB or C# (altough VB is more preferable)

thanks for reading this
GeneralA Petition :o)
JAC_Sharp
0:27 4 Jul '07  
Hello again Gustavo,

It would be nice that in the cases where the function fails to find the path,it return the best possible path in order to go the close possible to the target.

For example, if the number of nodes reach the limit the path returned should be the best path that it found when it reeached the limit.

Also, when there is no possible path (the target is in a closed zone) it should return the path that leads to the more possible position near the target.

Perhaps, could be an option for the PathFinder class to determinate what return when the algorithm fails (null or the best path possible), something like:
bool ReturnNullPathIfFails = true;

Regards!
GeneralWhy so poor precision?
jarribas
3:25 2 Jul '07  
First of all, thank you fou your great job.

Testing the code I've found that the code works with intenger and every time is making truncation of the values computed. The worst of them is when computing of the cost of the path with heavy diagonals (next peace of code):
if (mHeavyDiagonals && i>3)
newG = parentNode.G + (int) (mGrid[newNode.X, newNode.Y] * 2.41);

This code is equal to this due to the int truncation:
if (mHeavyDiagonals && i>3)
newG = parentNode.G + 2 * mGrid[newNode.X, newNode.Y]

For this reason the path found is not the optimal and is not natural. Why don't you use fixed point operations? Simply, multiply all the cost by 100 (G and H) like this:
if (mHeavyDiagonals && i>3)
newG = parentNode.G + (int) (mGrid[newNode.X, newNode.Y] * 141);

and son on in the rest of the code, always multiplying the cost of mGrid by 100 before doing any operation.

Try this and see the results for your self. And this change doesn't affect to the good performance of your algorithm.




GeneralRe: Why so poor precision?
CastorTiu
4:17 2 Jul '07  
Hi jarribas,

The speed difference between int/float was barely noticeable but mainly I did not use float because of the amount of nodes to be reevaluated, on int the amount of nodes is minimal, I did not want to sacrifice performance for a very similar result path.

In the code that you show above are not the same:

If the new node has a value of 50 and parent 40 then :

My Code:
if (mHeavyDiagonals && i>3)
newG = parentNode.G + (int) (mGrid[newNode.X, newNode.Y] * 2.41);
160 = 40 + (int) (50 * 2.41)
160 = 40 + (int) (120.5)

Your Code:
if (mHeavyDiagonals && i>3)
newG = parentNode.G + 2 * mGrid[newNode.X, newNode.Y]
140 = 40 + 2 * 50
140 = 40 + 100

Anyway I'll think about multiplying by 100.

Thanks for the comment,
Gustavo.



--
If you think the chess rules are not fair, first beat Anand, Kasparov and Karpov then you can change them.
Moral is, don't question the work of others if you don't know the reason why they did it.

GeneralRe: Why so poor precision?
JAC_Sharp
5:14 2 Jul '07  
Yes, of course I agree with you in not using float point operations, instead of that, you can get two decimal digits precision operations with only multiplying the values by 100.

With great weight numbers, your code is very similar:
160 = 40 + (int) (50 * 2.41)


But with lower weights like 1 then the code is equal to :

newG = parentNode.G + (int) (1 * 2.41) = parentNode.G + 2; // 20% of error due to the truncation of 2.41

In my way:
newG = parentNode.G + (int) (1 * 241) = parentNode.G + 241;

(in most situations like your demo application the default weight is 1)

Another thing: Why using 2.41 for computing the diagonals? It should be 1.41 (sqrt(2), I've modified the code with these minor changes and with Euclidean formula and heavy diagonals the result is perfect (the path is more natural like a human would make).

Overall, your class is great, I'll vote 5 for you Blush )


GeneralRe: Why so poor precision?
CastorTiu
6:00 2 Jul '07  
>> Another thing: Why using 2.41 for computing the diagonals? It should be 1.41 (sqrt(2), I've modified the code with these minor changes and with Euclidean formula and heavy diagonals the result is perfect (the path is more natural like a human would make).

If you use 1.41 then you are not punishing the diagonal.

Neither my solution or yours is the right way to do it.

If you use 1.41 then the diagonal will never be punished because if you multiply the source node by 1.41 the result will always be less than go for the non-diagonal in two steps.

Imagine one node in the top-left (0,0) and you want to go to (1,1) with node cost of 1.

Starting to right or bottom you will have a cost of 2, right and then down, or bottom then right.

The diagonal cost with 1.41 will be less than 2 then the algorith still will go with the diagonal, so the diagonal will never be punished.

I use 2.41 becuse is the cost of going diagonal plus a punishing factor (1) in my case, so for that reason is 2.41 (1.41 real cost + punishing factor).

If you use 1.41 then will not be difference wheter you use punish diagonal or not.

The real formula should have been calculate the real cost of going diagonal plus a punishing factor, to calulate the real cost the algorithm must evaluate the hypotenuse of the two adjacent nodes and add a punishing factor.

If the direction is in the first quadrant (0,0) to (1,1) then the algorithm should do.

newG = parentNode.G + (sqr(matrix[parentNode.X + 1, parentNode.Y] ^ 2 + matrix[parentNode.X, parentNode.Y + 1] ^ 2) + punishfactor);

that should be evaluated against the right quadrant in the algoritm.

As you can see this will reduce the performance of the algorithm, so using 2.41 will get the same result as the previous formula when the parent and adjacent nodes have cost 1, which is the most of cases.

Regards,
Gustavo.

--
If you think the chess rules are not fair, first beat Anand, Kasparov and Karpov then you can change them.
Moral is, don't question the work of others if you don't know the reason why they did it.

GeneralRe: Why so poor precision?
JAC_Sharp
8:10 2 Jul '07  
Ahm, that's right, if you want to punish using diagonals 2.41 factor is ok.

In the code you have two options:

- Heavy Diagonals: Cost = Cost*2.41
- Normal Diagonals: Cost = Cost*1

And I want using diagonals with the real cost of diagonal that is:
Cost = Cost*SQRT(2) = Cost * 1.41

In this way, using Euclidean, heuristic value is exactly the distance from the point to the tarjet, and the G cost is exactly the distance walked.

Ahm, in the code for download there is a bug in PathFinderFast in the computing of the heuristic euclidean formula (a Y variable of the first operand should be a X).




GeneralRe: Why so poor precision?
CastorTiu
10:50 2 Jul '07  
Good catch, thank you for the bug finding.

I'll update the code whenever I can and upload again.

For the rest of people to know, please replace the line:

mH = (int) (mHEstimate * Math.Sqrt(Math.Pow((mNewLocationY - end.X) , 2) + Math.Pow((mNewLocationY - end.Y), 2)));

by

mH = (int) (mHEstimate * Math.Sqrt(Math.Pow((mNewLocationX - end.X) , 2) + Math.Pow((mNewLocationY - end.Y), 2)));

Regards,
Gustavo

--
If you think the chess rules are not fair, first beat Anand, Kasparov and Karpov then you can change them.
Moral is, don't question the work of others if you don't know the reason why they did it.

GeneralA* algorithm [modified]
tran manh tuan
6:04 1 Jun '07  
Hi Mr CastorTiu!
I'm loving your article about A* algorithm implementation in C#. I have saw the source that you posted but i have only one question to you!
I don't know A* algorithm --> can you tell me description about it. I have searched much article but i haven't got suite information! Example: http://en.wikipedia.org/wiki/A*_search_algorithm. Could you help me to send article or document that describe A* algorithm?

please contact with me by email: tuantmyb@gmail.com


-- modified at 20:57 Saturday 2nd June, 2007
GeneralRe: A* algorithm
tran manh tuan
16:00 3 Jun '07  
hi everybody!
anyone has email of Mr CastorTiu? Please send it to me ! I want to ask him some information! Thanks!
tuantmyb@gmail.com
GeneralVery Nice!
merlin981
12:49 24 May '07  
Your article and code have been very helpful. I had my own implementation of A*, but yours is much faster. I also appreciated your details about how you streamlined your code to make it faster and more efficient.


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I get my developer tools from Merlin A.I. Soft
I get my news and jokes from Daily Roundup
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Generalis there a vis c++ version
jhsmith246
13:59 23 May '07  
excellent learning tool for me to understand search algorithm--i was wondering if there is a mfc 6.0 version?
thank you.

GeneralRe: is there a vis c++ version
CastorTiu
11:27 24 May '07  
I'm sorry I do not have a c++ version, but C# is a lot easier than C++ and the way how to program it is very similar, you should not have trouble at all to understand the code.

Regards,
Gustavo.

--
If you think the chess rules are not fair, first beat Anand, Kasparov and Karpov then you can change them.
Moral is, don't question the work of others if you don't know the reason why they did it.

GeneralRe: is there a vis c++ version
jhsmith246
8:30 29 May '07  
ok, thanks, i will try and figure it out.
GeneralRe: is there a vis c++ version-last question
jhsmith246
8:49 29 May '07  
gustavo: since i will need to get another compiler to run this would your program run under current .net compiler or does it require c# compiler?

thanks,
jeff


Generalask about map lazily
exe_exe_5
3:50 7 Jan '07  
Isn't it inefficient to create byte[] grid from my own map before pathfinding, when it is only needed to examine few ten nodes?
Wouldn't it be faster to ask about move cost/possibility lazily by some GetCost(x,y) delegate/interface?
GeneralI did that too
Jcmorin
10:19 29 Sep '06  
I did a few years ago a Path Finding Engine using a custom algorithm... not based on A* because I wanted my search to be scalable to millions of cell and be able to continue searching if the map changed dynamically... take a look
http://jcmorin.net/pfe/[^]

I know is unsafe to try an .exe but trust me you can get cool result.

map of 400*320 with 45 000 block give cool search result.
GeneralProblem
Henize
16:26 21 Sep '06  
It goes strait through walls. Even when they are perfectly strait.

static int Sqrt(int x) { if (x<0) throw new ArgumentOutOfRangeException(); int temp, y=0, b=0x8000, bshft=15, v=x; do { if (v>=(temp=(y<<1)+b<<bshft--)) { y+=b; v-=temp; } } while ((b>>=1)>0); return y; OMG

GeneralRe: Problem
CastorTiu
18:37 21 Sep '06  
What is it?

I guess you replied the wrong article. Laugh

Regards,
Gustavo.
QuestionRe: Problem
Henize
18:50 21 Sep '06  
I was using the 80 button instead of the X buttonD'Oh!

Im trying to create a .dll and it contains a class called SimplePathFinder. Its an implimintation of the A* algorithm. It finds the path but it rarely makes diagonal moves. Im frustrated with A*, can you help me out? Its very clean and simple code, can you take a look and see what I need to do to make it move diagonal when its supposed to? You seem to understand A* very well and I would greatly appresiate your help.

I looked through your code but I cannot get a good understanding becuase yours is so flexable and I cant spot what I need.

static int Sqrt(int x) { if (x<0) throw new ArgumentOutOfRangeException(); int temp, y=0, b=0x8000, bshft=15, v=x; do { if (v>=(temp=(y<<1)+b<<bshft--)) { y+=b; v-=temp; } } while ((b>>=1)>0); return y; OMG

AnswerRe: Problem
CastorTiu
15:47 22 Sep '06  
Sure, post or send me the code, I'll see what I can do.

Regards,
Gustavo.


Last Updated 24 May 2007 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010