我目前正在使用A *算法学习和编程寻路(在Java中)。我遇到的一个问题是,当多个实体尝试寻路时,它们都会改变previousNode
(计算出Node
的{{1}}),弄乱了算法,最终Node
将指向Node A
,Node B
将指向Node B
。
如何将算法更改为
Node A
系统(我已经看过,就是这样)我试图避免让一个实体完成寻路,然后告诉下一个实体寻路,等等。就像在Java中执行previousNode
- wait()
对一样。
notify()
我具体谈到(public Path findPath(int startX, int startY, int goalX, int goalY) {
//Path is basically just a class that contains an ArrayList,
//containing Nodes, which contains the steps to reach a goal.
if(map.getNode(goalX, goalY).isObstacle()) {
return null;
}
map.getNode(startX, startY).setDistanceFromStart(0);
closedList.clear();
openList.clear(); //A List with added getFirst() - gets the first Node in the list
openList.add(map.getNode(startX, startY));
while(openList.size() != 0) {
//Node contains a List that has all of the Nodes around this node, a
//F, G, and H value, and its row(y) and column(x)
Node current = openList.getFirst();
if(current.getX() == goalX && current.getY() == goalY) {
return backtrackPath(current);
}
openList.remove(current);
closedList.add(current);
for(Node neighbor : current.getNeighborList()) {
boolean neighborIsBetter;
//If I've already searched this neighbor/node, don't check it
if(closedList.contains(neighbor)) {
continue;
}
if(!neighbor.isObstacle()) {
float neighborDistanceFromStart = (current.getDistanceFromStart() + map.getDistanceBetween(current, neighbor));
if(!openList.contains(neighbor)) {
openList.add(neighbor);
neighborIsBetter = true;
} else if(neighborDistanceFromStart < current.getDistanceFromStart()) {
neighborIsBetter = true;
} else {
neighborIsBetter = false;
}
if(neighborIsBetter) {
neighbor.setPreviousNode(current);
neighbor.setDistanceFromStart(neighborDistanceFromStart);
neighbor.setHeuristic(getManhattanDistance(neighbor.getX(), neighbor.getY(), goalX, goalY));
}
}
}
}
return null;
}
public Path backtrackPath(Node fromNode) {
Path path = new Path();
while(fromNode.getPreviousNode() != null) {
path.prependWaypoint(fromNode);
fromNode = fromNode.getPreviousNode();
}
return path;
}
内)
findPath()
答案 0 :(得分:1)
我认为你不能以某种方式为给定路径存储一个backpointer,你可以做A *(或任何寻路算法)。所以这给你留下了两个选择
选项1是相当不言自明的,可能是更好的选择。如果这只是为了你,你应该只使用那个(而不是试图在一个图上使A *完全并发)。这将需要添加map
作为输入参数(并要求并发调用应使用不同的映射实例,如果不发生则抛出异常或具有未指定的行为)。此外,您应该将closedList
和openList
实例化为每个调用中的新数据结构,而不是共享列表。
如果这不符合您的喜好 - 您真的希望将多重调用用法完全封装到方法本身中,我认为最简单的方法就是需要一个额外的id
参数 - 一些独特的保证不与另一个并发调用的id
相同的字符串。所以A *的标题现在看起来像:
public Path findPath(final String ID, int startX, int startY, int goalX, int goalY) {
从那里,将Node
中每个可设置路径查找字段的所有实现更改为HashMap
,并将id
作为关键字。从你的代码中,我猜你的Node
类看起来像这样:
public class Node{
//Fields used by the A* call - no problem here
private boolean obstacle;
//Fields *edited* by the A* call
private float distanceFromStart;
private Node previous;
private int heuristic;
//other fields and stuff
public boolean isObstacle(){
return obstacle;
}
public float getDistanceFromStart(){
return distanceFromStart;
}
public void setDistanceFromStart(float f){
distanceFromStart = f;
}
public Node getPrevious(){
return previous;
}
public void setPrevious(Node p){
previous = p;
}
public int getHeuristic(){
return heuristic;
}
public void setHeuristic(int h){
heuristic = h;
}
}
我们可以修改已修改字段,以便能够按id
存储多个值:
public class Node{
//Fields used by the A* call - no problem here
private boolean obstacle;
//Fields *edited* by the A* call
private HashMap<String,Float> distanceFromStart;
private HashMap<String,Node> previous;
private HashMap<String,Integer> heuristic;
//other fields and stuff
public boolean isObstacle(){
return obstacle;
}
public float getDistanceFromStart(String id){
return distanceFromStart.get(id);
}
public void setDistanceFromStart(String id, float f){
distanceFromStart.put(id, f);
}
public Node getPrevious(String id){
return previous.get(id);
}
public void setPrevious(String id, Node p){
previous.put(id,p);
}
public int getHeuristic(String id){
return heuristic.get(id);
}
public void setHeuristic(String id,int h){
heuristic.put(id,h);
}
}
从那里开始,只需编辑你的A *方法,在调用时将方法调用的id提供给getter和setter。只要两个并发方法调用没有相同的id
值,它们就不会相互干扰。要记住三件事要正确使用:
无论哪种方式,无论您采用何种并发方法,您仍然应该制作openList
和closedList
个新本地实例。制作openList
和closedList
共享实例没有任何好处,只有错误才能实现。
List<Node> closedList = new LinkedList<Node>();
List<Node> openList = new LinkedList<Node>();
//Don't have to clear them anymore - they're new lists
openList.add(map.getNode(startX, startY));