Enhance path finding using path cost
This commit is contained in:
@@ -54,54 +54,52 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
|
||||
return p;
|
||||
}
|
||||
|
||||
public Path? GetFreePath(IEnumerable<INode> points, bool overrideStart = false) {
|
||||
if (overrideStart) {
|
||||
return GetPath(points, (n) => n is not ISink && (n is not Valve v || !v.LockedForPaths.Any(p => p.Start != points.First())));
|
||||
} else {
|
||||
return GetPath(points, (n) => n is not ISink && (n is not Valve v || !v.IsLocked));
|
||||
}
|
||||
}
|
||||
|
||||
public Path? GetPath(IEnumerable<INode> points, Func<INode, bool>? valid = null) {
|
||||
public Path? GetPath(IEnumerable<INode> points, Func<INode, bool>? valid = null, Func<Path, int>? cost = null) {
|
||||
if (points.Count() < 2) return null;
|
||||
var start = points.First();
|
||||
var path = new Path(start, []);
|
||||
List<Path> paths = [new(start, [])];
|
||||
foreach (var end in points.Skip(1)) {
|
||||
if (valid != null && start != points.First() && !valid(start)) {
|
||||
if (valid != null && start != points.First() && !valid(start))
|
||||
return null;
|
||||
} else if (GetPath(start, end, valid, visited: [.. path.Hops.Select(h => h.Node)]) is not Path p) {
|
||||
return null;
|
||||
} else {
|
||||
path.Hops = [.. path.Hops, .. p.Hops];
|
||||
start = end;
|
||||
|
||||
var newPaths = new List<Path>();
|
||||
foreach (var path in paths) {
|
||||
foreach (var subPath in GetPaths(start, end, visited: [.. path.Hops.Select(h => h.Node)], valid)) {
|
||||
newPaths.Add(new(path.Start, [.. path.Hops, .. subPath.Hops]));
|
||||
}
|
||||
}
|
||||
if (newPaths.Count == 0)
|
||||
return null;
|
||||
|
||||
paths = newPaths;
|
||||
start = end;
|
||||
}
|
||||
if (paths.Count == 0) {
|
||||
return null;
|
||||
} else {
|
||||
cost ??= p => 0;
|
||||
return paths.OrderBy(cost).First();
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
public Path? GetPath(INode start, INode end, Func<INode, bool>? valid = null, HashSet<INode>? visited = null) {
|
||||
public IEnumerable<Path> GetPaths(INode start, INode end, HashSet<INode>? visited = null, Func<INode, bool>? valid = null) {
|
||||
if (!Nodes.Contains(start) || !Nodes.Contains(end)) throw new ArgumentException("Start/end node not contained in graph");
|
||||
valid ??= a => true;
|
||||
visited = [.. visited ?? [], start];
|
||||
List<(IEdge, INode)> hops = [];
|
||||
Path? path = null;
|
||||
foreach (var o in start.Outputs) {
|
||||
var e = o.IsTwoWay && o.End == start ? o.Start : o.End;
|
||||
if (e == end) {
|
||||
return new(start, [(o, e)]);
|
||||
yield return new(start, [(o, e)]);
|
||||
continue;
|
||||
} else if (!valid(e) || visited.Contains(e)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var p = GetPath(e, end, valid, visited);
|
||||
if (p != null) {
|
||||
var p2 = new Path(start, [(o, e), .. p.Value.Hops]);
|
||||
if (path == null || p2.Bends < path.Value.Bends || (p2.Bends == path.Value.Bends && p2.Length < path.Value.Length)) {
|
||||
path = p2;
|
||||
}
|
||||
foreach (var p in GetPaths(e, end, visited, valid)) {
|
||||
yield return new(start, [(o, e), .. p.Hops]);
|
||||
}
|
||||
}
|
||||
return path != null ? new(start, path.Value.Hops) : null;
|
||||
}
|
||||
|
||||
public void Draw(Canvas canvas) {
|
||||
|
||||
Reference in New Issue
Block a user