A * Wikipedia search algorithm takes a lot of time

I have successfully implemented A * pathfinding in C #, but it is very slow and I do not understand why. I didn't even try to sort the openNodes list, but it's still the same.

The card has a size of 80x80 and 10-11 nodes.

I took the pseudocode here Wikipedia

And this is my implementation:

 public static List<PGNode> Pathfind(PGMap mMap, PGNode mStart, PGNode mEnd)
    {
        mMap.ClearNodes();

        mMap.GetTile(mStart.X, mStart.Y).Value = 0;
        mMap.GetTile(mEnd.X, mEnd.Y).Value = 0;

        List<PGNode> openNodes = new List<PGNode>();
        List<PGNode> closedNodes = new List<PGNode>();
        List<PGNode> solutionNodes = new List<PGNode>();

        mStart.G = 0;
        mStart.H = GetManhattanHeuristic(mStart, mEnd);

        solutionNodes.Add(mStart);
        solutionNodes.Add(mEnd);

        openNodes.Add(mStart); // 1) Add the starting square (or node) to the open list.

        while (openNodes.Count > 0) // 2) Repeat the following:
        {
            openNodes.Sort((p1, p2) => p1.F.CompareTo(p2.F));

            PGNode current = openNodes[0]; // a) We refer to this as the current square.)

            if (current == mEnd)
            {
                while (current != null)
                {
                    solutionNodes.Add(current);
                    current = current.Parent;
                }

                return solutionNodes;
            }

            openNodes.Remove(current);
            closedNodes.Add(current); // b) Switch it to the closed list.

            List<PGNode> neighborNodes = current.GetNeighborNodes();
            double cost = 0;
            bool isCostBetter = false;

            for (int i = 0; i < neighborNodes.Count; i++)
            {
                PGNode neighbor = neighborNodes[i];
                cost = current.G + 10;
                isCostBetter = false;

                if (neighbor.Passable == false || closedNodes.Contains(neighbor))
                    continue; // If it is not walkable or if it is on the closed list, ignore it.

                if (openNodes.Contains(neighbor) == false)
                {
                    openNodes.Add(neighbor); // If it isn’t on the open list, add it to the open list.
                    isCostBetter = true;
                }
                else if (cost < neighbor.G)
                {
                    isCostBetter = true;
                }

                if (isCostBetter)
                {
                    neighbor.Parent = current; //  Make the current square the parent of this square. 
                    neighbor.G = cost;
                    neighbor.H = GetManhattanHeuristic(current, neighbor);
                }
            }
        }

        return null;
    }

Here's the heuristic I'm using:

    private static double GetManhattanHeuristic(PGNode mStart, PGNode mEnd)
    {
        return Math.Abs(mStart.X - mEnd.X) + Math.Abs(mStart.Y - mEnd.Y);
    }

What am I doing wrong? This is the whole day when I keep looking at the same code.

+3
source share
6 answers

, . , , ; , . . , . - ? , , .

-, , , . , , ?

( , , , " " " " - , , , . 14 -, 10 , 10 20 .)

A * , , . - " ", , .

?

, " " ? . ( .)

-, , , . , ; , .

-, A * # 3 , ; , .

http://blogs.msdn.com/b/ericlippert/archive/tags/astar/

; :

var closed = new HashSet<Node>();
var queue = new PriorityQueue<double, Path<Node>>();
queue.Enqueue(0, new Path<Node>(start));
while (!queue.IsEmpty)
{
    var path = queue.Dequeue();
    if (closed.Contains(path.LastStep)) continue;
    if (path.LastStep.Equals(destination)) return path;
    closed.Add(path.LastStep);
    foreach(Node n in path.LastStep.Neighbours)
    {
        double d = distance(path.LastStep, n);
        var newPath = path.AddStep(n, d);
        queue.Enqueue(newPath.TotalCost + estimate(n), newPath);
    }
}

, ; , . , ; , . , , () .

-, . , , , , , , .

+16

:

List<T> . . Stack<T> Queue<T>.

List.Remove(current) . , , .

openNodes, , , . , . , .

, closedNodes, - , closedNodes.Contains(). , , . Set<T>. , node . , closedNodes .

- solutionNodes, , mEnd mStart , .

neighborNodes IEnumerable<T> List<T>, . foreach , .

+5

( ) A * quickgraph:

QuickGraph.Algorithms.ShortestPath.AStarShortestPathAlgorithm<TVertex,TEdge>
+1

? Red Gate. Performance Profiler, , , Memory Profiler, , - , .

@Rodrigo, . , .

0

node, :

cost = current.G + 10;

. ? , , .

"", : current.GetNeighborNodes. ? node, , node node ?

0

? , Octile:

= (min ( x, y) * 2 + max ( x, y) - min ( x, y))

. , .

. (100 x 100), . , , , pop_back. , . node, . n, , .

Finally, if the speed is so high that you are using Jump Point Search. This is, on average, 20-30 times faster than finding the A * path without memory overhead (or, as stated in the research paper, they found no evidence about this). It will basically replace the “find neighbors” step in * with “find successors”, so incorporating it into your code should be relatively simple.

Hope this helps.

-1
source

Source: https://habr.com/ru/post/1789274/


All Articles