A-Star寻路|六角形握把

时间:2017-08-26 11:28:28

标签: java algorithm path-finding a-star hexagonal-tiles

我是新手,我面临着这样一个尴尬的问题:

img

似乎算法吞下了额外的十六进制。 有人能指出我的错误吗?

所以这是代码:

(1和2中出现的'ob'是'障碍'的集合)

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.以下是以下节点和比较器类:

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 个答案:

答案 0 :(得分:1)

TreeSet不适合此用法。它是根据比较器(忽略equals的实现)来定义的,但是在Open集中具有相同F分数的多个节点(确实需要在那里)是可能的和通用的。这将导致应该存在的节点丢失,以及重复的无意义存在。

在插入节点之前移除节点并不是一个真正的解决方案,只是一个快速的黑客(显然)使它在某些时候工作。您不应该将该建议视为可接受的解决方案,应该应用基本的改变。

通常提到的方法是维护链接的优先级队列和哈希映射,其中优先级队列更新哈希映射以跟踪具有给定坐标的节点在队列中的位置。这样可以查询&#34;包含&#34;的开放集。快速(hashmap),快速从队列中删除带有给定坐标的节点(hashmap,然后告诉队列删除给定索引处的节点),并且仍然可以快速访问F分数最低的节点(像往常一样) )。

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