Enhance path finding using path cost

This commit is contained in:
2026-08-11 02:01:08 +02:00
parent f0accc8df8
commit 03c91fb55a
3 changed files with 49 additions and 34 deletions
+25 -27
View File
@@ -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) {