A* 在遍历它的路径回到开始节点时有时会永远循环
A* sometimes loops forever when traversing it's path back to the begin node
我尝试了 2 种不同的伪代码,来自 Wikipedia and MIT,最终都给我相同的结果:
有时,就像在这些屏幕截图上一样,永远循环遍历,因为不知何故以某种方式出现了 link :
我在 AS3 中包含代码:
{
private function searchPath(e:MouseEvent = null):void
{
for (var i:int = 0; i < nodes.length; i ++)
nodes[i].role = Node.IDLE_NODE;
if (!endNode || !beginNode) return;
beginNode.role = Node.BEGIN_NODE;
endNode.role = Node.END_NODE;
openSet.push(beginNode);
beginNode.g = 0;
beginNode.f = beginNode.h = heuristicCost(beginNode, endNode);
addEventListener(Event.ENTER_FRAME, update);
}
private function update(e:Event):void
{
if (openSet.length)
{
// searching for minimal f score node
var current:Node = openSet[0];
for (var i:int = 0; i < openSet.length; i ++)
if (openSet[i].f < current.f)
{
current = openSet[i];
}
current.role = Node.CURRENT_NODE;
// remove current node from openset
openSet.splice(openSet.indexOf(current), 1);
// walking through neighbours
for each(var neighbour:Node in current.neighbours)
{
if (neighbour == endNode)
{
neighbour.parentNode = current;
highlightPath(neighbour);
return;
}
if (current.g + heuristicCost(current, neighbour) >= neighbour.g)
continue;
neighbour.g = current.g + heuristicCost(current, neighbour);
neighbour.h = heuristicCost(neighbour, endNode);
neighbour.f = neighbour.g + neighbour.h;
// if neighbour is in the closed set or is in the openthen skip it
if (!(closedSet.indexOf(neighbour) > -1) && (openSet.indexOf(neighbour) < 0))
{
openSet.push(neighbour);
neighbour.parentNode = current;
}
}
// add current node to the closed set
closedSet.push(current);
}
else
{
while (closedSet.length) closedSet.pop();
trace("No solution");
removeEventListener(Event.ENTER_FRAME, update);
}
}
private function highlightPath(current:Node):void
{
var tp:Vector.<Node> = new Vector.<Node>();
tp.push(current);
while (current.parentNode) //this loops forever in situations from screenshots, because there's a link back
{
tp.push(current.parentNode);
current.role = Node.PATH_NODE;
current = current.parentNode;
}
current.role = Node.PATH_NODE;
while (openSet.length) openSet.pop();
while (closedSet.length) closedSet.pop();
for (var i:int = 0; i < nodes.length; i ++)
nodes[i].g = nodes[i].h = nodes[i].f = Infinity;
removeEventListener(Event.ENTER_FRAME, update);
}
}
不要在意距离!该路径是最优的,更近的节点没有连接(我在屏幕截图中隐藏了连接)。
还有,忘了说截图上的开始节点是黑色的,不是橙色的。
抱歉,伙计们,我犯了一个非常愚蠢的错误,我忘记在第一个 运行 之后将我的节点的 parentNodes 重置为 null。
设置neighbour.g
时应设置neighbour.parentNode = current
。现在,您正在将 parentNode
设置为将 neighbor
推送到 openSet
的第一个节点
此外,如果您使用适当的数据结构 (closedSet
的集合;优先级队列openSet
)
我尝试了 2 种不同的伪代码,来自 Wikipedia and MIT,最终都给我相同的结果:
有时,就像在这些屏幕截图上一样,永远循环遍历,因为不知何故以某种方式出现了 link :
我在 AS3 中包含代码:
{
private function searchPath(e:MouseEvent = null):void
{
for (var i:int = 0; i < nodes.length; i ++)
nodes[i].role = Node.IDLE_NODE;
if (!endNode || !beginNode) return;
beginNode.role = Node.BEGIN_NODE;
endNode.role = Node.END_NODE;
openSet.push(beginNode);
beginNode.g = 0;
beginNode.f = beginNode.h = heuristicCost(beginNode, endNode);
addEventListener(Event.ENTER_FRAME, update);
}
private function update(e:Event):void
{
if (openSet.length)
{
// searching for minimal f score node
var current:Node = openSet[0];
for (var i:int = 0; i < openSet.length; i ++)
if (openSet[i].f < current.f)
{
current = openSet[i];
}
current.role = Node.CURRENT_NODE;
// remove current node from openset
openSet.splice(openSet.indexOf(current), 1);
// walking through neighbours
for each(var neighbour:Node in current.neighbours)
{
if (neighbour == endNode)
{
neighbour.parentNode = current;
highlightPath(neighbour);
return;
}
if (current.g + heuristicCost(current, neighbour) >= neighbour.g)
continue;
neighbour.g = current.g + heuristicCost(current, neighbour);
neighbour.h = heuristicCost(neighbour, endNode);
neighbour.f = neighbour.g + neighbour.h;
// if neighbour is in the closed set or is in the openthen skip it
if (!(closedSet.indexOf(neighbour) > -1) && (openSet.indexOf(neighbour) < 0))
{
openSet.push(neighbour);
neighbour.parentNode = current;
}
}
// add current node to the closed set
closedSet.push(current);
}
else
{
while (closedSet.length) closedSet.pop();
trace("No solution");
removeEventListener(Event.ENTER_FRAME, update);
}
}
private function highlightPath(current:Node):void
{
var tp:Vector.<Node> = new Vector.<Node>();
tp.push(current);
while (current.parentNode) //this loops forever in situations from screenshots, because there's a link back
{
tp.push(current.parentNode);
current.role = Node.PATH_NODE;
current = current.parentNode;
}
current.role = Node.PATH_NODE;
while (openSet.length) openSet.pop();
while (closedSet.length) closedSet.pop();
for (var i:int = 0; i < nodes.length; i ++)
nodes[i].g = nodes[i].h = nodes[i].f = Infinity;
removeEventListener(Event.ENTER_FRAME, update);
}
}
不要在意距离!该路径是最优的,更近的节点没有连接(我在屏幕截图中隐藏了连接)。
还有,忘了说截图上的开始节点是黑色的,不是橙色的。
抱歉,伙计们,我犯了一个非常愚蠢的错误,我忘记在第一个 运行 之后将我的节点的 parentNodes 重置为 null。
设置neighbour.g
时应设置neighbour.parentNode = current
。现在,您正在将 parentNode
设置为将 neighbor
推送到 openSet
此外,如果您使用适当的数据结构 (closedSet
的集合;优先级队列openSet
)