A-Star Pathfinding |六角手柄

问题描述:

我是一个新手,我面临着这样一个尴尬的问题:A-Star Pathfinding |六角手柄

img

好像算法吞下一个额外的十六进制。 有人可以指出我的错误吗?

因此,这里的代码:

( 'OB' 出现在图1和2被设置的 '障碍')

1.Pathfinding FUNC:

private static Node pathFinding(Vector2i startHex, Vector2i goalHex, HashSet<Vector2i> ob, int movesLeft) { 
    start = new Node(startHex); 
    goal = new Node(goalHex); 

    if (distance(start, goal) > movesLeft) return null; 

    TreeSet<Node> openSet = new TreeSet<>(new NodeComparator()); 
    HashSet<Node> closedSet = new HashSet<>(); 

    start.cameFrom = null; 
    start.g = 0; 
    start.h = distance(start, goal); 
    start.f = start.g + start.h; 
    openSet.add(start); 

    float tentativeScore; 

    while (!openSet.isEmpty()) { 
     current = openSet.pollFirst(); 
     if (current.coords.equals(goal.coords)) { 
      return current; 
     } 
     closedSet.add(current); 
     for (Node node : getNeighbors(current, ob)) { 
      node.g = distance(start, node); 
      tentativeScore = current.g + distance(current, node); 

      if (!closedSet.contains(node) || tentativeScore < node.g) { 
       node.g = tentativeScore; 
       node.h = distance(node, goal); 
       node.f = node.g + node.h; 
       node.cameFrom = current; 
       openSet.add(node); 
      } 
     } 
    } 
    return null; 
} 

2.Neighbors :

private static final Vector2i[] directions2i = { 
     new Vector2i(0,-1), new Vector2i(1,-1), new Vector2i(1,0), 
     new Vector2i(0,1), new Vector2i(-1,1), new Vector2i(-1,0) 
}; 

private static List<Node> getNeighbors(Node origin, HashSet<Vector2i> ob) { 
    List<Node> list = new ArrayList<>(); 
    for (int i = 0; i < 6; i++) { 
     Vector2i dir = new Vector2i(origin.coords.x + directions2i[i].x, origin.coords.y + directions2i[i].y); 
     if (!ob.contains(dir)) 
      list.add(new Node(dir)); 
    } 
    return list; 
} 

3.Heuristic:

static float distance(Node a, Node b) { 
    return (Math.abs(a.coords.x - b.coords.x) + Math.abs(a.coords.y - b.coords.y) + Math.abs(a.coords.x +a.coords.y -b.coords.x -b.coords.y))/2; 
} 

4.And以防万一这里是节点和比较类:

public class Node { 
public Node cameFrom; 
public Vector2i coords; 
float g, h, f; 

@Override 
public int hashCode() { 
    return coords.x * 100000 + coords.y; 
} 

@Override 
public boolean equals(Object o) { 
    if (this == o) return true; 
    if (getClass() != o.getClass()) return false; 
    Node oth = (Node) o; 
    return this.coords.equals(oth.coords); 
} 

Node(Vector2i coords) { 
    this.coords = new Vector2i(coords); 
} 
} 

private static class NodeComparator implements Comparator<Node> { 
    @Override 
    public int compare(Node o1, Node o2) { 
     return Float.compare(o1.f, o2.f); 
    } 
} 
+1

不是一个答案,但:该代码是一个有点难以阅读和理解,特别是很难“调试”只是看它。但是,如果你没有找到它自己:在http://www.redblobgames.com/grids/hexagons有关于六边形网格的*优秀资源(包括邻居搜索,距离计算,甚至是障碍物寻路) – Marco13

+0

'openSet.add'是否返回'false'? – harold

+0

@ Marco13感谢您提供有用的信息! – GrastaSsS

TreeSet不适合这种用法。它是在比较器(忽略equals实现)来定义,但它有可能也经常会有多个节点(即真正需要的是那里)具有相同的F值的开集。这会导致本应该出现的节点丢失,以及无意义的重复出现。

插入它不是顺便说一个真正的解决方案,只是一个快速的黑客工具,(显然)使得它的工作一定的时间之前删除节点。你不应该认为这个建议是一个可接受的解决方案,应该应用根本性的改变。

一个常提到的方法是维持一个链接的优先级队列和哈希表,其中优先级队列更新哈希表来跟踪在那里与给定坐标节点在队列中出现的。这使得能够快速地查询Open集合“contains”(hashmap),快速从队列中移除具有给定坐标的节点(hashmap,然后告诉队列移除给定索引处的节点),并且仍然提供快速访问到最低F分数的节点(像往常一样)。

这种安排不能与内置的进行有序的容器,因为队列需要知道散列映射和更新。幸运的是,二进制堆并不难实现,并且它已经完成了,因此您可能可以借用现有的实现。

+0

谢谢,我会做的! – GrastaSsS

+0

我想过使用简单优先级队列,因为我不需要“包含”和“删除给定坐标的节点”来打开设置。是对的吗? – GrastaSsS

+1

@GrastaSsS然后在Open集合中将会有“死亡节点”,这些节点对应于次优前缀,因此永远不会对最佳路由做出贡献,并且在评估这些路径时浪费时间。但它仍然应该找到最佳路径。 – harold