Fix HierarchicalPathFinder failing to consider multiple source locations.
When asked to find a path from multiple source locations, the abstract search is used to determine which source locations are viable. Source locations that cannot be reached on the abstract graph are excluded from the local path search. As we know the locations are unreachable, this prevents the local path search from expanding over the entire search space in an attempt to find these unreachable locations, preventing wasted effort. In order to determine these reachable locations, the abstract search is expanded successively trying to reach each source location each time. However, this failed to account for a property of the ExpandToTarget for which a comment is now added. If the location was found previously, then expanding to try and find it again will fail. If the source locations were close together, it was likely that the initial expansions of the search space would have included them, and thus they would not be found on a later expansion. This would mean these locations would incorrectly be thought unreachable. To fix this, we check if the location has already been explored (has CellStatus.Closed in the graph). If so we can check the cost to determine if it is reachable.
This commit is contained in:
@@ -629,9 +629,19 @@ namespace OpenRA.Mods.Common.Pathfinder
|
||||
var sourcesWithPathableNodes = new List<CPos>(sourcesWithReachableNodes.Count);
|
||||
foreach (var source in sourcesWithReachableNodes)
|
||||
{
|
||||
reverseAbstractSearch.TargetPredicate = cell => cell == source;
|
||||
if (reverseAbstractSearch.ExpandToTarget())
|
||||
sourcesWithPathableNodes.Add(source);
|
||||
// Check if we have already found a route to this node before we attempt to expand the search.
|
||||
var sourceStatus = reverseAbstractSearch.Graph[source];
|
||||
if (sourceStatus.Status == CellStatus.Closed)
|
||||
{
|
||||
if (sourceStatus.CostSoFar != PathGraph.PathCostForInvalidPath)
|
||||
sourcesWithPathableNodes.Add(source);
|
||||
}
|
||||
else
|
||||
{
|
||||
reverseAbstractSearch.TargetPredicate = cell => cell == source;
|
||||
if (reverseAbstractSearch.ExpandToTarget())
|
||||
sourcesWithPathableNodes.Add(source);
|
||||
}
|
||||
}
|
||||
|
||||
if (sourcesWithPathableNodes.Count == 0)
|
||||
@@ -900,8 +910,8 @@ namespace OpenRA.Mods.Common.Pathfinder
|
||||
var abstractCell = gridInfo.AbstractCellForLocalCell(cell).Value;
|
||||
var info = graph[abstractCell];
|
||||
|
||||
// Expand the abstract search if we have not visited the abstract cell.
|
||||
if (info.Status == CellStatus.Unvisited)
|
||||
// Expand the abstract search only if we have yet to get a route to the abstract cell.
|
||||
if (info.Status != CellStatus.Closed)
|
||||
{
|
||||
abstractSearch.TargetPredicate = c => c == abstractCell;
|
||||
if (!abstractSearch.ExpandToTarget())
|
||||
|
||||
@@ -241,6 +241,11 @@ namespace OpenRA.Mods.Common.Pathfinder
|
||||
/// <summary>
|
||||
/// Expands the path search until a path is found, and returns whether a path is found successfully.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If the path search has previously been expanded it will only return true if a path can be found during
|
||||
/// *this* expansion of the search. If the search was expanded previously and the target is already
|
||||
/// <see cref="CellStatus.Closed"/> then this method will return false.
|
||||
/// </remarks>
|
||||
public bool ExpandToTarget()
|
||||
{
|
||||
while (CanExpand())
|
||||
|
||||
Reference in New Issue
Block a user