2017-08-26 106 views
0

我是一個新手,我面臨着這樣一個尷尬的問題: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

回答

1

TreeSet不適合這種用法。它是在比較器(忽略equals實現)來定義,但它有可能也經常會有多個節點(即真正需要的是那裏)具有相同的F值的開集。這會導致本應該出現的節點丟失,以及無意義的重複出現。

插入它不是順便說一個真正的解決方案,只是一個快速的黑客工具,(顯然)使得它的工作一定的時間之前刪除節點。你不應該認爲這個建議是一個可接受的解決方案,應該應用根本性的改變。

一個常提到的方法是維持一個鏈接的優先級隊列和哈希表,其中優先級隊列更新哈希表來跟蹤在那裏與給定座標節點在隊列中出現的。這使得能夠快速地查詢Open集合「contains」(hashmap),快速從隊列中移除具有給定座標的節點(hashmap,然後告訴隊列移除給定索引處的節點),並且仍然提供快速訪問到最低F分數的節點(像往常一樣)。

這種安排不能與內置的進行有序的容器,因爲隊列需要知道散列映射和更新。幸運的是,二進制堆並不難實現,並且它已經完成了,因此您可能可以借用現有的實現。

+0

謝謝,我會做的! – GrastaSsS

+0

我想過使用簡單優先級隊列,因爲我不需要「包含」和「刪除給定座標的節點」來打開設置。是對的嗎? – GrastaSsS

+1

@GrastaSsS然後在Open集合中將會有「死亡節點」,這些節點對應於次優前綴,因此永遠不會對最佳路由做出貢獻,並且在評估這些路徑時浪費時間。但它仍然應該找到最佳路徑。 – harold