星型算法不起作用

时间:2018-01-18 19:50:31

标签: java algorithm a-star

我基于维基百科页面link to page上的伪代码为A *实现了这个算法,但它找不到任何路径。当我使用它时,我永远不会到达当前节点等于目标的点。我认为它可能与我的启发式或我初始化f和g分数的方式有关,但我似乎无法弄明白。

我正在使用的地图大小是1920 x 1080,并使用30的单元格大小。

private ArrayList<Vector2> aStar(Vector2 start, Vector2 goal) {
    HashSet<Vector2> closedSet = new HashSet<Vector2>();
    ArrayList<Vector2> openSet = new ArrayList<Vector2>();
    openSet.add(start);
    HashMap<Vector2,Vector2> cameFrom = new HashMap<Vector2, Vector2>();
    HashMap<Vector2,Float> gScore = new HashMap<Vector2, Float>();
    HashMap<Vector2,Float> fScore = new HashMap<Vector2, Float>();
    ArrayList<Vector2> neighbors = new ArrayList<Vector2>();
    neighbors.add(new Vector2(0,30));
    neighbors.add(new Vector2(0,-30));
    neighbors.add(new Vector2(30,0));
    neighbors.add(new Vector2(-30,0));
    for(int i = 0; i < 1920; i +=30){
        for(int j = 0; j < 1080; j +=30){
            gScore.put(new Vector2(i,j),Float.MAX_VALUE);
            fScore.put(new Vector2(i,j),Float.MAX_VALUE);
        }
    }
    gScore.put(start,0f);
    fScore.put(start,heuristic(start,goal));

    while(!openSet.isEmpty()){
        int low = 0;
        for(int i = 0; i < openSet.size(); i++){
            if(fScore.get(openSet.get(i))<fScore.get(openSet.get(low))){
                low = i;
            }
        }
        Vector2 current = openSet.get(low);
        if(current.equals(goal)){
            System.out.println("YES!");
            return null;
        }
        openSet.remove(current);
        closedSet.add(current);
        for(Vector2 neighbor:neighbors){
            Vector2 tst = new Vector2(neighbor.x + current.x,neighbor.y + current.y);
            if(tst.x > -30 && tst.x <1920 && tst.y > -30 && tst.y < 1080){
                neighbor.add(current);
                if(closedSet.contains(neighbor)){
                    continue;
                }
                if(!openSet.contains(neighbor)){
                    openSet.add(neighbor);
                }

                float tentative_gScore = gScore.get(current) + heuristic(current,neighbor);
                if(tentative_gScore >= gScore.get(neighbor)){
                    continue;
                }

                cameFrom.put(neighbor,current);
                gScore.put(neighbor,tentative_gScore);
                fScore.put(neighbor,gScore.get(neighbor)+heuristic(neighbor,goal));
            }
        }

    }

    return null;
}

private float heuristic(Vector2 begin, Vector2 end) {
    return  (Math.abs(begin.x - end.x) + Math.abs(begin.y - end.y)) ;
}

2 个答案:

答案 0 :(得分:0)

neighbor.add(current);更改了邻居。不仅如此,而且您存储了该邻居,这意味着将保留此对象引用,并且可能在将来的代码中进一步失真。

另一个问题是你的启发式问题。您正在使用曼哈顿距离,这意味着存在大量具有相同距离的路径(只要您永远不会离开目标节点,每条路径的距离都相同)。尝试允许对角线邻居,并使用欧几里德距离而不是曼哈顿距离。

答案 1 :(得分:0)

在所有代码中都很难找到错误。我会尝试,但我认为解决这个问题的更好方法会对你有帮助。

考虑创建一个名为Node的类,对于每个Node n,它具有以下项目:

  • 节点的路径
  • f(n)的值,从开始到n的路径的成本
  • g(n)的值,启发式的成本,这是从n到目标。
  • 元素或标签。

然后是递归解的伪代码:

search_a_star(frontier)
    if(frontier.isEmpty())
       return false
    //Select node with lower f(n) + g(n)
    node = selectNode(frontier)
    if node is goal then 
       return node //You have in the node the cost and the path
    else
       //Generate the neighbours of your current node. You should calculate the heuristing of each neighbour.
       neighbours = generateNeighbours(node)
       //Add neighbours to reducedFrontier
       reducedFrontier = frontier - node
       newFrontier = add(reducedFrontier, neighbours) 
       search_a_star(newFrontier)

您应该保留一组可访问的节点。此外,当您生成邻居时,您应该考虑这种情况进行循环控制:

  1. 如果未访问生成的节点,则应将其添加到邻居集中。
  2. 如果已访问生成的节点,但路径的成本低于之前的值,则应从访问集中删除该节点并将其添加到邻居集中。
  3. 否则,请勿将节点添加到邻居集。