Search code examples
javapath-findinga-star

a* pathFinding, implementation not working correctly? any suggestions?


hi i am implementing an a* path finder using the manhattan distance as a cost, can seem to wrap my head around it: heres the code for the search,

 public LinkedList<MapNode> search(MapNode startNode, MapNode goalNode) {

    LinkedList<MapNode> closedList = new LinkedList<MapNode>();
    LinkedList<MapNode> openList = new LinkedList<MapNode>();

    openList.add(startNode);

    startNode.setPathParent(null);

    while (!openList.isEmpty()) {
        MapNode node = (MapNode) openList.removeFirst();

        if (node == goalNode) 
            return constructPath(goalNode);

        else {
            closedList.add(node);

            // add neighbors to the open list
            Iterator<MapNode> i = getNeighbours(node, goalNode).iterator();

            while (i.hasNext()) {
                MapNode neighborNode = (MapNode) i.next();

                if (!closedList.contains(neighborNode) && !openList.contains(neighborNode)) {
                        neighborNode.setPathParent(node);
                        openList.add(neighborNode);

                }
            }
        }
    }
    // no path found
    return null;
}

and heres my getneighbours() method:

public LinkedList<MapNode> getNeighbours(MapNode node, MapNode goalNode) {

    Position positionCheck = new Position(0, 0);

    for (int x = -1; x < 2; x++){

        int newX = node.getPosition().getPositionX() + x;
        if(newX<0 || newX >= Map.DIMENSION){continue;}

        for (int y = -1; y < 2; y++){

            int newY = node.getPosition().getPositionY() + y;
            if(newY<0 || newY >= Map.DIMENSION){continue;}

            positionCheck.setPositionX(newX);
            positionCheck.setPositionY(newY);

            if(!node.getPosition().equals(positionCheck)){
                calculateCost(map.elementAt(positionCheck), goalNode);

                neighbours.add(map.elementAt(positionCheck));
            }
        }

    }   

    return neighbours;
}

It works but unfortunately its not using the manhattan principle, the output is this:

 Shortest Delivery Point is: 6 miles! - 8,7 // using manhattan distance
 S = Start, D=Destination, "."= path taken.


 [3,4] ->
 [4,3] ->
 [5,4] ->
 [6,5] ->
 [ D ] ->

 [0,0]  [0,1]  [0,2]  [0,3]  [0,4]  [0,5]  [0,6]  [0,7] 
 [1,0]  [1,1]  [1,2]  [1,3]  [1,4]  [1,5]  [1,6]  [1,7] 
 [2,0]  [2,1]  [2,2]  [2,3]  [2,4]  [ S ]  [2,6]  [2,7] 
 [3,0]  [3,1]  [3,2]  [3,3]  [ . ]  [3,5]  [3,6]  [3,7] 
 [4,0]  [4,1]  [4,2]  [ . ]  [4,4]  [4,5]  [4,6]  [4,7] 
 [5,0]  [5,1]  [5,2]  [5,3]  [ . ]  [5,5]  [5,6]  [5,7] 
 [6,0]  [6,1]  [6,2]  [6,3]  [6,4]  [ . ]  [6,6]  [6,7] 
 [7,0]  [7,1]  [7,2]  [7,3]  [7,4]  [7,5]  [ D ]  [7,7] 

I was just wondering if anyone could spot what i cant, its the first time i've messed about with pathfinding so i am a bit niaeve. Thanks for the help..


Solution

  • The node that you take off the open list must be the node with the smallest F cost. That makes using a linked list a bad choice - you either have to search through it completely to extract a node, or you have to search through it completely to insert nodes. But, bad choice or not, it's not correct like this because you're doing neither.

    Also, if a neighbour is already in the open list, you must compare the G scores and re-parent it if the new path is better.

    Using a linked list for the closed set is also a bad choice, you only need "add" and "contains" on it, and contains is terrible for linked lists. This doesn't affect correctness though.