diff --git a/OpenRa.Game/OpenRa.Game.csproj b/OpenRa.Game/OpenRa.Game.csproj
index a620d9e68f..a1610c7cc9 100644
--- a/OpenRa.Game/OpenRa.Game.csproj
+++ b/OpenRa.Game/OpenRa.Game.csproj
@@ -40,6 +40,7 @@
x86
false
prompt
+ true
bin\x86\Release\
diff --git a/OpenRa.Game/PathFinder.cs b/OpenRa.Game/PathFinder.cs
index 9cda2e0e11..b1e812746d 100644
--- a/OpenRa.Game/PathFinder.cs
+++ b/OpenRa.Game/PathFinder.cs
@@ -97,7 +97,14 @@ namespace OpenRa.Game
prev = sl;
}
if (queue.Empty) return new List();
- var ret = FindPath(cellInfo, queue, estimator, umt, true);
+
+ var h2 = DefaultEstimator(path[0]);
+ var otherQueue = new PriorityQueue();
+ otherQueue.Add(new PathDistance(h2(from), from));
+
+ var ret = FindBidiPath(cellInfo, InitCellInfo(), queue, otherQueue, estimator, h2, umt, true);
+
+ //var ret = FindPath(cellInfo, queue, estimator, umt, true);
ret.Reverse();
return ret;
}
@@ -124,53 +131,26 @@ namespace OpenRa.Game
List FindPath( CellInfo[ , ] cellInfo, PriorityQueue queue, Func estimator, UnitMovementType umt, bool checkForBlock )
{
- int samples = 0;
+ int nodesExpanded = 0;
using (new PerfSample("find_path_inner"))
{
while (!queue.Empty)
{
PathDistance p = queue.Pop();
- int2 here = p.Location;
- cellInfo[here.X, here.Y].Seen = true;
+ cellInfo[p.Location.X, p.Location.Y].Seen = true;
- if (estimator(here) == 0.0)
+ if (estimator(p.Location) == 0)
{
- PerfHistory.Increment("nodes_expanded", samples * .01);
- return MakePath(cellInfo, here);
+ PerfHistory.Increment("nodes_expanded", nodesExpanded * .01);
+ return MakePath(cellInfo, p.Location);
}
- samples++;
+ nodesExpanded++;
- foreach (int2 d in Util.directions)
- {
- int2 newHere = here + d;
-
- if (cellInfo[newHere.X, newHere.Y].Seen)
- continue;
- if (passableCost[(int)umt][newHere.X, newHere.Y] == float.PositiveInfinity)
- continue;
- if (!Game.BuildingInfluence.CanMoveHere(newHere))
- continue;
- if (checkForBlock && Game.UnitInfluence.GetUnitAt(newHere) != null)
- continue;
- var est = estimator(newHere);
- if (est == float.PositiveInfinity)
- continue;
-
- float cellCost = ((d.X * d.Y != 0) ? 1.414213563f : 1.0f) * passableCost[(int)umt][newHere.X, newHere.Y];
- float newCost = cellInfo[here.X, here.Y].MinCost + cellCost;
-
- if (newCost >= cellInfo[newHere.X, newHere.Y].MinCost)
- continue;
-
- cellInfo[newHere.X, newHere.Y].Path = here;
- cellInfo[newHere.X, newHere.Y].MinCost = newCost;
-
- queue.Add(new PathDistance(newCost + est, newHere));
- }
+ ExpandNode(cellInfo, queue, p, umt, checkForBlock, estimator);
}
- PerfHistory.Increment("nodes_expanded", samples * .01);
+ PerfHistory.Increment("nodes_expanded", nodesExpanded * .01);
// no path exists
return new List();
}
@@ -211,6 +191,98 @@ namespace OpenRa.Game
return 1.5f * diag + straight;
};
}
+
+ void ExpandNode(CellInfo[,] ci, PriorityQueue q, PathDistance p, UnitMovementType umt, bool checkForBlock, Func h)
+ {
+ foreach (int2 d in Util.directions)
+ {
+ int2 newHere = p.Location + d;
+
+ if (ci[newHere.X, newHere.Y].Seen)
+ continue;
+ if (passableCost[(int)umt][newHere.X, newHere.Y] == float.PositiveInfinity)
+ continue;
+ if (!Game.BuildingInfluence.CanMoveHere(newHere))
+ continue;
+ if (checkForBlock && Game.UnitInfluence.GetUnitAt(newHere) != null)
+ continue;
+ var est = h(newHere);
+ if (est == float.PositiveInfinity)
+ continue;
+
+ float cellCost = ((d.X * d.Y != 0) ? 1.414213563f : 1.0f) * passableCost[(int)umt][newHere.X, newHere.Y];
+ float newCost = ci[p.Location.X, p.Location.Y].MinCost + cellCost;
+
+ if (newCost >= ci[newHere.X, newHere.Y].MinCost)
+ continue;
+
+ ci[newHere.X, newHere.Y].Path = p.Location;
+ ci[newHere.X, newHere.Y].MinCost = newCost;
+
+ q.Add(new PathDistance(newCost + est, newHere));
+ }
+ }
+
+ List FindBidiPath( /* searches from both ends toward each other */
+ CellInfo[,] ca,
+ CellInfo[,] cb,
+ PriorityQueue qa,
+ PriorityQueue qb,
+ Func ha,
+ Func hb,
+ UnitMovementType umt,
+ bool checkForBlocked)
+ {
+ while (!qa.Empty && !qb.Empty)
+ {
+ { /* make some progress on the first search */
+ var p = qa.Pop();
+ ca[p.Location.X, p.Location.Y].Seen = true;
+
+ if (cb[p.Location.X, p.Location.Y].MinCost < float.PositiveInfinity)
+ return MakeBidiPath(ca, cb, p.Location);
+ else
+ ExpandNode(ca, qa, p, umt, checkForBlocked, ha);
+ }
+
+ { /* make some progress on the second search */
+ var p = qb.Pop();
+ cb[p.Location.X, p.Location.Y].Seen = true;
+
+ //if (ca[p.Location.X, p.Location.Y].MinCost < float.PositiveInfinity)
+ // return MakeBidiPath(ca, cb, p.Location);
+ //else
+ ExpandNode(cb, qb, p, umt, checkForBlocked, hb);
+ }
+ }
+
+ return new List();
+ }
+
+ static List MakeBidiPath(CellInfo[,] ca, CellInfo[,] cb, int2 p)
+ {
+ var a = new List();
+ var b = new List();
+
+ var q = p;
+ while (ca[q.X, q.Y].Path != q)
+ {
+ q = ca[q.X, q.Y].Path;
+ a.Add(q);
+ }
+
+ q = p;
+ while (cb[q.X, q.Y].Path != q)
+ {
+ q = cb[q.X, q.Y].Path;
+ b.Add(q);
+ }
+
+ a.Add(p);
+ for (var v = b.Count - 1; v >= 0; v--) a.Add(b[v]);
+
+ return a;
+ }
}
struct CellInfo