Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm attempting to implement A* pathfinding in my game, and it works for most of the iterations I've tested it with, but I've hit a few random cases where it never stops loading items into the Closed and Open lists, making me think I have a leak in my logic somewhere. I think it's caused when there are multiple options that have equal G+H values, and it even happens when the origin and target are only 2-3 steps apart, but I'm not sure how to protect against multiple equal values.

This implementation is based on the Wikipedia pseudocode and some other helpers I've found around the web:

private Point getNextPoint(Point sourceLoc, Point targetLoc)
{
    // clear the lists
    openList.Clear();
    closedList.Clear();
    // find direction of targetLoc
    GridFacing facing = findFacing(sourceLoc, targetLoc);
    // get starting adjacent locations
    foreach (Node node in getNeighbors(new Node(sourceLoc.X, sourceLoc.Y), (int)facing, targetLoc))
    {
        openList.Add(node);
    }

    Node previous = new Node();
    while (openList.Count > 0)
    {
        // current lowest G+H
        int indexS = openList.Min(f => f.F);
        // get next node with lowest G+H that is not the previous node
        Node node = openList.First(f => f.F == indexS && f != previous);
        // check for goal
        if (node.Loc == targetLoc)
        {
            return recurseNextNode(node).Loc;
        }
        // remove from openset
        openList.Remove(node);
        // add to closedset
        closedList.Add(node);
        // get neighbors of current location
        List<Node> sortedNeighbors = getNeighbors(node, (int)facing, targetLoc);
        foreach (Node neighbor in sortedNeighbors)
        {
            // not in closed set
            if (closedList.Contains(neighbor))
                continue;
            // steps from source
            int tempG = node.G + 1;
            // not already in openset or temp g less than existing g;
            if (!openList.Any(f => f.Loc == neighbor.Loc && f.G == tempG) || tempG < neighbor.G)
            {
                neighbor.Parent = node;
                neighbor.G = tempG;
                neighbor.H = Convert.ToInt32(GetDistance(neighbor.Loc, targetLoc));
                if (!openList.Contains(neighbor) && !closedList.Contains(neighbor))
                    openList.Add(neighbor);
            }
        }
        previous = node;
    }

    return new Point(0, 0);
}

What in this implementation is allowing for these massive loops, and how do I protect against it?

share|improve this question

closed as off-topic by Anko, BlueRaja - Danny Pflughoeft, Noctrine Feb 10 '14 at 19:59

  • This question does not appear to be about game development within the scope defined in the help center.
If this question can be reworded to fit the rules in the help center, please edit the question.

3  
I would avoid adding "Debug my code"-style posts on GD.SE. You may want to try codereview.stackexchange.com. –  Shotgun Ninja Feb 10 '14 at 19:10
2  
FWIW, you have more than enough data here to try and walk through the code yourself - if it literally never stops loading items into the list then you're somehow failing in your logic of never loading an item that's already in an open or closed list, and you should be able to step through with a specific example in mind to see why it's adding a point it should never be able to add. –  Steven Stadnicki Feb 10 '14 at 19:11
2  
This question appears to be off-topic because it is about debugging your code for you. –  Anko Feb 10 '14 at 19:29

1 Answer 1

You have some serious performance issues, which could cause the behavior you're seeing in large graphs.

Here are some tips:

  1. You don't need typically need a closedList in real-life - having a HasBeenVisited property on the Node will serve the equivalent purpose, but be much faster.
  2. Your openList doesn't appear to be a priority queue, so operations like Dequeue() and Contains() will be O(n) rather than O(log n).

    I've released a C# PriorityQueue implementation designed specifically for high-performance pathfinding. It does Dequeue() in O(log n) and Contains() in O(1).

share|improve this answer

Not the answer you're looking for? Browse other questions tagged or ask your own question.