java - A星探路 |六角握把

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

我是新手,遇到了这么尴尬的问题:

img .

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

代码如下:

(出现在1和2中的'ob'是一组'obstacles')

1.寻路功能:

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.邻居:

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.启发式:

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. 为了以防万一,这里有 Node 和 Comparator 类:

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);
    }
}

最佳答案

TreeSet 不适合这种用法。它是根据比较器定义的(忽略 equals 的实现),但在 Open 中有多个节点(确实需要存在)具有相同的 F 分数是可能的,也是常见的放。这将导致本应存在的节点丢失,以及毫无意义的重复出现。

顺便说一句,在插入节点之前删除节点并不是一个真正的解决方案,这只是一个(显然)使其在某些时候起作用的快速破解。您不应将该建议视为可接受的解决方案,应进行根本性的更改。

一种通常提到的方法是维护链接的优先级队列和 HashMap ,其中优先级队列更新 HashMap 以跟踪具有给定坐标的节点在队列中出现的位置。这使得能够快速查询“包含”的 Open 集(hashmap),快速从队列中删除具有给定坐标的节点(hashmap,然后告诉队列删除给定索引处的节点),并且仍然提供快速访问到 F 分数最低的节点(像往常一样)。

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

关于java - A星探路 |六角握把,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45894845/

相关文章:

java - 如何在 Hibernate 中序列化集合属性?

java - Spark : Remove Content-Type header

algorithm - 如何将 Levenshtein 距离应用于一组目标字符串?

algorithm - 在强制唯一节点属性的同时进行寻路——我应该使用哪种算法?

c++ - 递归算法的实现

java - JSOUP 中的 MIME 类型

java - 在运行时扫描 Java 注释

algorithm - 寻找快速算法来查找二叉树中两个节点之间的距离

algorithm - 计算线性序列模 n 的总和

php - 寻路算法找到从一个地方到另一个地方的路线