static void Main(string[] args) { var input = File.ReadAllLines("../../../input.txt"); var sw = new Stopwatch(); sw.Start(); var wires = input.Select(WireToPoints).ToList(); var crossings = new HashSet <Point>(wires[0].Keys.Intersect(wires[1].Keys)); var closest = crossings.MinBy(DistanceFromOrigin).First(); Console.WriteLine($"Part 1: point {closest} is in both wires and close to the origin."); var shortest = crossings.MinBy(x => wires[0][x] + wires[1][x]).First(); var delay = wires[0][shortest] + wires[1][shortest]; Console.WriteLine($"Part 2: point {shortest} has signal delay {delay}"); var search1 = new BreadthFirstSearch <Point>(EqualityComparer <Point> .Default, p => _mapDirectionToSize.Values.Select(s => p + s).Where(wires[0].Keys.Contains) ) { PerformParallelSearch = false }; var wire1 = search1.FindAll(Point.Empty, p => crossings.Contains(p)) .ToDictionary(x => x.Target, x => x.Length); var search2 = new BreadthFirstSearch <Point>(EqualityComparer <Point> .Default, p => _mapDirectionToSize.Values.Select(s => p + s).Where(wires[1].Keys.Contains) ) { PerformParallelSearch = false }; var wire2 = search2.FindAll(Point.Empty, p => crossings.Contains(p)) .ToDictionary(x => x.Target, x => x.Length); var shortedCrossings = crossings.MinBy(x => wire1[x] + wire2[x]).First(); delay = wire1[shortedCrossings] + wire2[shortedCrossings]; Console.WriteLine($"Part 3: point {shortedCrossings} has signal delay {delay}"); sw.Stop(); Console.WriteLine($"Solving took {sw.ElapsedMilliseconds}ms."); _ = Console.ReadLine(); }
/// <summary> /// Computes the result of the operation. /// </summary> protected override void ComputeResult() { _edgeSet = new HashSet <IGraphEdge>(); _forest = new DisjointSetForest <IGraphVertex>(Source.Vertices); while (_forest.SetCount > 1) { IGraphVertex currentRep = null; foreach (IGraphVertex vertex in _forest.OrderedEnumerator) { if (currentRep != _forest.Find(vertex)) { //new component currentRep = _forest.Find(vertex); if (_edgeSet.Count > 0) { _spanningEdges.Add(_edgeSet.MinBy(x => _weightMetric(x)).First()); } _edgeSet.Clear(); } if (Source.OutEdges(vertex).Any(x => _forest.Find(x.Target) != currentRep)) { _edgeSet.Add( Source.OutEdges(vertex) .Where(x => _forest.Find(x.Target) != currentRep) .MinBy(y => _weightMetric(y)) .First()); } } if (_edgeSet.Count > 0) { //on the last element there is no component change _spanningEdges.Add(_edgeSet.MinBy(x => _weightMetric(x)).First()); } _edgeSet.Clear(); foreach (IGraphEdge spanningEdge in _spanningEdges) { _forest.Union(spanningEdge.Source, spanningEdge.Target); } } }
public static int Dijkstra(this Dictionary <Point, int> graph, Point source, Point target) { var Q = new HashSet <Point>(); var dist = new Dictionary <Point, int>(); var prev = new Dictionary <Point, Point?>(); foreach (var v in graph.Keys) { dist[v] = int.MaxValue; prev[v] = null; Q.Add(v); } dist[source] = 0; while (Q.Count > 0) { var u = Q.MinBy(p => dist[p]) !; Q.Remove(u); foreach (var v in u.Neighbors(target).Intersect(Q)) { var alt = dist[u] + graph[v]; if (alt < dist[v]) { dist[v] = alt; prev[v] = u; } } } var seq = new List <(Point, int, int)>(); var p = target; while (p is not null) { seq.Add((p, graph[p], dist[p]));
// Split any edges that intersect with the given edge at their midpoint. private static void SplitEdgesWithEdge(List <Vector2> vertexes, List <IntTuple2> edges, IntTuple2 splitterEdge) { // Gather edge split data. These are tuples in the form (splitter vertex index, split edge index). List <IntTuple2> edgeSplitData = new List <IntTuple2>(); HashSet <int> splitEdgeVertsSet = new HashSet <int>(); splitEdgeVertsSet.Add(splitterEdge.e0); splitEdgeVertsSet.Add(splitterEdge.e1); for (int i = 0; i < edges.Count; ++i) { IntTuple2 curEdge = edges[i]; int intersectionIndex = MakeIntersection(vertexes, splitterEdge, curEdge); // If the current edge had a vertex on the splitter edge, split the splitter edge but leave the current egde alone. if (curEdge.e0 == intersectionIndex || curEdge.e1 == intersectionIndex) { Debug.Log("Will split edge [" + vertexes[splitterEdge.e0] + ", " + vertexes[splitterEdge.e1] + "] at " + vertexes[intersectionIndex]); splitEdgeVertsSet.Add(intersectionIndex); } // If the splitter edge had a vertex on the current edge, split the current edge but leave the splitter edge alone. else if (splitterEdge.e0 == intersectionIndex || splitterEdge.e1 == intersectionIndex) { Debug.Log("Will split edge [" + vertexes[curEdge.e0] + ", " + vertexes[curEdge.e1] + "] at " + vertexes[intersectionIndex]); edgeSplitData.Add(new IntTuple2(intersectionIndex, i)); } // If the edges met in the middle, split them both. else if (intersectionIndex != -1) { Debug.Log("Will split edge [" + vertexes[splitterEdge.e0] + ", " + vertexes[splitterEdge.e1] + "] at " + vertexes[intersectionIndex]); Debug.Log("Will split edge [" + vertexes[curEdge.e0] + ", " + vertexes[curEdge.e1] + "] at " + vertexes[intersectionIndex]); splitEdgeVertsSet.Add(intersectionIndex); edgeSplitData.Add(new IntTuple2(intersectionIndex, i)); } } // DEBUG: Log stuff to figure out why splitting doesn't work as expected. /*if (edgeSplitData.Count > 0) * { * string debugText = "Edge split data:\n"; * foreach (IntTuple2 splitData in edgeSplitData) * { * int vertexIndex = splitData.e0; * int edgeIndex = splitData.e1; * * Vector2 vertex = vertexes[vertexIndex]; * IntTuple2 edge = edges[edgeIndex]; * * debugText += ("[" + vertexes[edge.e0] + ", " + vertexes[edge.e1] + "] was split at " + vertex + "\n"); * } * Debug.Log(debugText); * } * * if (splitEdgeVertsSet.Count > 0) * { * string debugText = "Split edge verts set:\n"; * foreach (int vert in splitEdgeVertsSet) * { * debugText += vertexes[vert]; * } * Debug.Log(debugText); * }*/ // Split the edges. foreach (IntTuple2 splitData in edgeSplitData) { int intersectionIndex = splitData.e0; int edgeIndex = splitData.e1; IntTuple2 edge = edges[edgeIndex]; // Split the old edge in two. int oldEnd = edge.e1; edge.e1 = intersectionIndex; IntTuple2 newEdge = new IntTuple2(intersectionIndex, oldEnd); if (!edges.Contains(newEdge)) { edges.Add(newEdge); } Debug.Log("Edge split into " + vertexes[edge.e0] + ", " + vertexes[intersectionIndex] + ", " + vertexes[newEdge.e1]); } // Make the new, split up edge to replace the old splitter edge from the vertexes. int[] splitEdgeVerts = new int[splitEdgeVertsSet.Count]; splitEdgeVertsSet.CopyTo(splitEdgeVerts); Vector2 mostNegative = vertexes[splitEdgeVertsSet.MinBy(v => vertexes[v].x + vertexes[v].y)]; System.Array.Sort <int>(splitEdgeVerts, (a, b) => { Vector2 vA = vertexes[a] - mostNegative; Vector2 vB = vertexes[b] - mostNegative; return(vA.sqrMagnitude.CompareTo(vB.sqrMagnitude)); } ); // DEBUG: Log the split edge verts. string debugText = "Split edge verts: "; foreach (int vertexIndex in splitEdgeVerts) { debugText += vertexes[vertexIndex] + ", "; } Debug.Log(debugText); // Create the new edges from the splitter edge data. for (int i = 1; i < splitEdgeVerts.Length; ++i) { int vA = splitEdgeVerts[i - 1]; int vB = splitEdgeVerts[i]; IntTuple2 newEdge = new IntTuple2(vA, vB); if (!edges.Contains(newEdge)) { edges.Add(newEdge); } } }
protected Job ResourceDeliverJobFor(Pawn pawn, IConstructible c, bool canRemoveExistingFloorUnderNearbyNeeders = true) { Blueprint_Install blueprint_Install = c as Blueprint_Install; if (blueprint_Install != null) { return(this.InstallJob(pawn, blueprint_Install)); } bool flag = false; ThingDefCountClass thingDefCountClass = null; List <ThingDefCountClass> list = c.MaterialsNeeded(); int count = list.Count; int i = 0; while (i < count) { ThingDefCountClass need = list[i]; if (!pawn.Map.itemAvailability.ThingsAvailableAnywhere(need, pawn)) { flag = true; thingDefCountClass = need; break; } Thing foundRes = GenClosest.ClosestThingReachable(pawn.Position, pawn.Map, ThingRequest.ForDef(need.thingDef), PathEndMode.ClosestTouch, TraverseParms.For(pawn, Danger.Deadly, TraverseMode.ByPawn, false), 9999f, (Thing r) => WorkGiver_ConstructDeliverResources.ResourceValidator(pawn, need, r), null, 0, -1, false, RegionType.Set_Passable, false); if (foundRes != null) { int resTotalAvailable; this.FindAvailableNearbyResources(foundRes, pawn, out resTotalAvailable); int num; Job job; HashSet <Thing> hashSet = this.FindNearbyNeeders(pawn, need, c, resTotalAvailable, canRemoveExistingFloorUnderNearbyNeeders, out num, out job); if (job != null) { return(job); } hashSet.Add((Thing)c); Thing thing = hashSet.MinBy((Thing nee) => IntVec3Utility.ManhattanDistanceFlat(foundRes.Position, nee.Position)); hashSet.Remove(thing); int num2 = 0; int j = 0; do { num2 += WorkGiver_ConstructDeliverResources.resourcesAvailable[j].stackCount; j++; }while (num2 < num && j < WorkGiver_ConstructDeliverResources.resourcesAvailable.Count); WorkGiver_ConstructDeliverResources.resourcesAvailable.RemoveRange(j, WorkGiver_ConstructDeliverResources.resourcesAvailable.Count - j); WorkGiver_ConstructDeliverResources.resourcesAvailable.Remove(foundRes); Job job2 = new Job(JobDefOf.HaulToContainer); job2.targetA = foundRes; job2.targetQueueA = new List <LocalTargetInfo>(); for (j = 0; j < WorkGiver_ConstructDeliverResources.resourcesAvailable.Count; j++) { job2.targetQueueA.Add(WorkGiver_ConstructDeliverResources.resourcesAvailable[j]); } job2.targetB = thing; if (hashSet.Count > 0) { job2.targetQueueB = new List <LocalTargetInfo>(); foreach (Thing current in hashSet) { job2.targetQueueB.Add(current); } } job2.targetC = (Thing)c; job2.count = num; job2.haulMode = HaulMode.ToContainer; return(job2); } else { flag = true; thingDefCountClass = need; i++; } } if (flag) { JobFailReason.Is(string.Format("{0}: {1}", WorkGiver_ConstructDeliverResources.MissingMaterialsTranslated, thingDefCountClass.thingDef.label), null); } return(null); }
private List <Node> DijkstraConnect(Node source, Node sink, out float routeCost) { string lastKey = "nokey"; routeCost = -1; StringBuilder sb = new StringBuilder(); try { List <Node> ret = null; Dictionary <Node, float> distances = new Dictionary <Node, float>(nodes.Count); Dictionary <Node, Node> previousNodes = new Dictionary <Node, Node>(nodes.Count); HashSet <Node> Q = new HashSet <Node>(nodes); Q.Add(sink); foreach (Node nd in nodes) { distances.SetOrAdd(nd, Single.PositiveInfinity); previousNodes.SetOrAdd(nd, null); } distances.SetOrAdd(sink, float.PositiveInfinity); previousNodes.SetOrAdd(sink, null); previousNodes.SetOrAdd(source, null); ZLogger.Message("DijkstraConnect", debugLevel: DebugLevel.Pathfinding); lastKey = "distances/source"; distances.SetOrAdd(source, 0); foreach (Node neighbor in source.neighbors) { distances[neighbor] = source.neighborDistances[neighbor]; } bool found = false; Node u = source; while (Q.Count > 0) { sb.Clear(); u = Q.MinBy((x) => distances[x]); //foreach (Node nd in u.neighbors) //{ // sb.Append($"nd = {nd}, distance = {distances[nd]}"); //} sb.Append($"Chose {u} as shortest with {distances[u]}- looking for sink {sink}"); ZLogger.Message(sb.ToString(), debugLevel: DebugLevel.Pathfinding); //Console.WriteLine(sb.ToString()); Q.Remove(u); if (u == sink) { break; } foreach (Node v in u.neighbors) { float altDistance = distances[u] + u.neighborDistances[v]; if (altDistance < distances[v]) { distances[v] = altDistance; previousNodes[v] = u; } } } sb.Clear(); foreach (Node node in previousNodes.Keys) { sb.Append($"Node:{node}, previous: {previousNodes[node]}, cumulative distance: {distances[node]}"); } ret = new List <Node>(); routeCost = distances[sink]; sb.Clear(); while (sink != null) { sb.AppendLine($"{sink}"); ret.Add(sink); sink = previousNodes[sink]; } ret.Add(source); sb.AppendLine($"Source Key = {source}"); ZLogger.Message(sb.ToString(), debugLevel: DebugLevel.Pathfinding); ret.Reverse(); return(ret); } catch (Exception e) { sb = new StringBuilder(); foreach (object v in e.Data.Keys) { sb.Append($"{e.Data[v]}: {v}"); } ZLogger.Message($"Couldn't find key! Or key was null... {lastKey} Exception data of type {e.GetType()} follows: {sb}", debugLevel: DebugLevel.Pathfinding); return(new List <Node>()); } }
DijkstraShortestPaths <TVertex, TEdge>( this IWeightedDirectedGraph <TVertex, TEdge> graph, TVertex origin, IAdder <TEdge> adder, IComparer <TEdge> comparer ) { if (graph == null) { throw new ArgumentNullException(nameof(graph)); } if (origin == null) { throw new ArgumentNullException(nameof(origin)); } if (adder == null) { throw new ArgumentNullException(nameof(adder)); } if (comparer == null) { throw new ArgumentNullException(nameof(comparer)); } if (!graph.Vertices.Contains(origin)) { throw new ArgumentException(); } // Constructs a dictionary which stores the graphs which contain the shortest path from the origin to // each of the vertices that is reachable from the origin by iteratively traversing successor endpoints. var graphs = new Dictionary <TVertex, IWeightedDirectedGraph <TVertex, TEdge> >(); // Constructs a dictionary which stores the additions which represent the added edges which in turn // represent the shortest path from the origin to each of the vertices when added. var accumulations = new Dictionary <TVertex, TEdge>(); var settledVertices = new HashSet <TVertex>(); var unsettledVertices = new HashSet <TVertex> { origin }; while (unsettledVertices.Count > 0) { // Returns the unsettled vertex that is nearest to the origin by finding the shortest of all the // accumulated edges which form a path from the origin to each of the unsettled vertices. Calling // the `MinBy` method with only one unsettled vertex in the set of unsettled vertices will return // that unsettled vertex, hence it will always return the origin during the first iteration over // the unsettled vertices set, because the unsettled vertices set will only contain the origin. var nearestVertex = unsettledVertices.MinBy(vertex => accumulations[vertex], comparer); // Removes the nearest vertex from the set of unvisited vertices. unsettledVertices.Remove(nearestVertex); // Iterates over each of the successor endpoints of the nearest vertex. foreach (var endpoint in graph.SuccessorEndpoints(nearestVertex)) { // If the vertex of the endpoint is already settled, then continue to the next iteration. if (settledVertices.Contains(endpoint.Vertex)) { continue; } // If the dictionary of additions contains an addition for the nearest vertex, then add this // addition and the endpoint edge together in order to calculate a single path from the origin // to the endpoint vertex of the current iteration; otherwise, an addition for the nearest vertex // does not exist so return the endpoint edge without adding. var currentPath = accumulations.ContainsKey(nearestVertex) ? adder.Add(accumulations[nearestVertex], endpoint.Edge) : endpoint.Edge; // Returns true if the dictionary of additions contains the endpoint vertex and the current path // is less than the existing shortest path from the origin to the endpoint vertex; otherwise, // false. The existing shortest path is taken from the addition of each of the endpoints from // the origin to the endpoint vertex which represent the existing shortest path when added. bool IsCurrentPathLessThanShortestPath() { return(accumulations.ContainsKey(endpoint.Vertex) && comparer.Compare(currentPath, accumulations[endpoint.Vertex]) < 0); } // If the dictionary of graphs does not contain a graph for the endpoint vertex or the current // path is less than the existing shortest path, then update the graph of the endpoint vertex. if (!graphs.ContainsKey(endpoint.Vertex) || IsCurrentPathLessThanShortestPath()) { // If the dictionary of graphs contains a graph for the nearest vertex, then a shortest path // from the origin to the nearest vertex already exists so return a copy of this graph; // otherwise, such a shortest path does not exist so return a new empty graph. var currentGraph = graphs.ContainsKey(nearestVertex) ? graphs[nearestVertex].EndpointPairs.ToGraph() : new WeightedDirectedGraph <TVertex, TEdge>(); // Adds an edge from the nearest vertex to the vertex of the endpoint. This means that the // graph will now contain endpoint pairs from the origin to the endpoint vertex. currentGraph.AddEdge(nearestVertex, endpoint.Vertex, endpoint.Edge); // Updates the graph of the endpoint vertex with the current graph because the current graph // contains a shorter path from the origin to the endpoint vertex than the existing graph. graphs[endpoint.Vertex] = currentGraph; // Updates the addition of the endpoint vertex with the current path for the same reason. accumulations[endpoint.Vertex] = currentPath; } // Adds the endpoint vertex to the set of unsettled vertices. unsettledVertices.Add(endpoint.Vertex); } // Adds the nearest vertex to the set of settled vertices. settledVertices.Add(nearestVertex); } return(graphs); }
protected Job ResourceDeliverJobFor(Pawn pawn, IConstructible c, bool canRemoveExistingFloorUnderNearbyNeeders = true) { Blueprint_Install blueprint_Install = c as Blueprint_Install; if (blueprint_Install != null) { return(InstallJob(pawn, blueprint_Install)); } bool flag = false; ThingDefCountClass thingDefCountClass = null; List <ThingDefCountClass> list = c.MaterialsNeeded(); int count = list.Count; for (int i = 0; i < count; i++) { ThingDefCountClass need = list[i]; if (!pawn.Map.itemAvailability.ThingsAvailableAnywhere(need, pawn)) { flag = true; thingDefCountClass = need; break; } Thing foundRes = GenClosest.ClosestThingReachable(pawn.Position, pawn.Map, ThingRequest.ForDef(need.thingDef), PathEndMode.ClosestTouch, TraverseParms.For(pawn), 9999f, (Thing r) => ResourceValidator(pawn, need, r)); if (foundRes != null) { FindAvailableNearbyResources(foundRes, pawn, out int resTotalAvailable); int neededTotal; Job jobToMakeNeederAvailable; HashSet <Thing> hashSet = FindNearbyNeeders(pawn, need, c, resTotalAvailable, canRemoveExistingFloorUnderNearbyNeeders, out neededTotal, out jobToMakeNeederAvailable); if (jobToMakeNeederAvailable != null) { return(jobToMakeNeederAvailable); } hashSet.Add((Thing)c); Thing thing = hashSet.MinBy((Thing nee) => IntVec3Utility.ManhattanDistanceFlat(foundRes.Position, nee.Position)); hashSet.Remove(thing); int num = 0; int num2 = 0; do { num += resourcesAvailable[num2].stackCount; num2++; }while (num < neededTotal && num2 < resourcesAvailable.Count); resourcesAvailable.RemoveRange(num2, resourcesAvailable.Count - num2); resourcesAvailable.Remove(foundRes); Job job = new Job(JobDefOf.HaulToContainer); job.targetA = foundRes; job.targetQueueA = new List <LocalTargetInfo>(); for (num2 = 0; num2 < resourcesAvailable.Count; num2++) { job.targetQueueA.Add(resourcesAvailable[num2]); } job.targetB = thing; if (hashSet.Count > 0) { job.targetQueueB = new List <LocalTargetInfo>(); foreach (Thing item in hashSet) { job.targetQueueB.Add(item); } } job.targetC = (Thing)c; job.count = neededTotal; job.haulMode = HaulMode.ToContainer; return(job); } flag = true; thingDefCountClass = need; } if (flag) { JobFailReason.Is($"{MissingMaterialsTranslated}: {thingDefCountClass.thingDef.label}"); } return(null); }
private void DoSearch(IEnumerable<Point> starts, Func<Point, bool> isPassable, Func<Point, bool> isGoal, Func<Point, Point, int> getCost, Func<Point, int> getH, int maxCost) { ClosedSet = new HashSet<Point>(); OpenSet = new HashSet<Point>(starts); CameFrom = new Dictionary<Point, Point>(); GScore = starts.ToDictionary(s => s, s => 0); FScore = starts.ToDictionary(s => s, s => GScore[s] + getH(s)); while (OpenSet.Any()) { var current = OpenSet.MinBy(p => FScore[p]); if (GScore[current] > maxCost) { return; } if (isGoal(current)) { Path = ConstructPath(CameFrom, current); return; } OpenSet.Remove(current); ClosedSet.Add(current); foreach (var n in GetNeighbors(current, isPassable)) { if (ClosedSet.Contains(n)) continue; var tentativeG = GScore[current] + getCost(current, n); if (!OpenSet.Contains(n) || tentativeG < GScore[n]) { CameFrom[n] = current; GScore[n] = tentativeG; FScore[n] = tentativeG + getH(n); OpenSet.Add(n); } } } }
private static TPoint FindNodeWithLowestScore <TPoint>(HashSet <TPoint> list, IDictionary <TPoint, float> scoreTable) { //return list.OrderBy(x => scoreTable[x.Value]).First().Value; return(list.MinBy(x => scoreTable[x])); }
public static bool ResourceDeliverJobFor(WorkGiver_ConstructDeliverResources __instance, ref Job __result, Pawn pawn, IConstructible c, bool canRemoveExistingFloorUnderNearbyNeeders = true) { Blueprint_Install blueprint_Install = c as Blueprint_Install; if (blueprint_Install != null) { __result = InstallJob(pawn, blueprint_Install); return(false); } List <Thing> resourcesAvailable = new List <Thing>(); bool flag = false; ThingDefCountClass thingDefCountClass = null; List <ThingDefCountClass> list = c.MaterialsNeeded(); int count = list.Count; for (int i = 0; i < count; i++) { ThingDefCountClass need = list[i]; if (!pawn.Map.itemAvailability.ThingsAvailableAnywhere(need, pawn)) { flag = true; thingDefCountClass = need; break; } Thing foundRes = GenClosest.ClosestThingReachable(pawn.Position, pawn.Map, ThingRequest.ForDef(need.thingDef), PathEndMode.ClosestTouch, TraverseParms.For(pawn), 9999f, (Thing r) => ResourceValidator(pawn, need, r)); if (foundRes != null) { resourcesAvailable.Clear(); //FindAvailableNearbyResources2(foundRes, pawn, out int resTotalAvailable, resourcesAvailable); int resTotalAvailable; int num0 = Mathf.Min(foundRes.def.stackLimit, pawn.carryTracker.MaxStackSpaceEver(foundRes.def)); resTotalAvailable = 0; resourcesAvailable.Add(foundRes); resTotalAvailable += foundRes.stackCount; if (resTotalAvailable < num0) { foreach (Thing item in GenRadial.RadialDistinctThingsAround(foundRes.Position, foundRes.Map, 5f, useCenter: false)) { if (resTotalAvailable >= num0) { break; } if (item.def == foundRes.def && GenAI.CanUseItemForWork(pawn, item)) { resourcesAvailable.Add(item); resTotalAvailable += item.stackCount; } } } int neededTotal; Job jobToMakeNeederAvailable; HashSet <Thing> hashSet = FindNearbyNeeders(pawn, need, c, resTotalAvailable, canRemoveExistingFloorUnderNearbyNeeders, out neededTotal, out jobToMakeNeederAvailable); if (jobToMakeNeederAvailable != null) { __result = jobToMakeNeederAvailable; return(false); } hashSet.Add((Thing)c); Thing thing = hashSet.MinBy((Thing nee) => IntVec3Utility.ManhattanDistanceFlat(foundRes.Position, nee.Position)); hashSet.Remove(thing); int num = 0; int num2 = 0; do { num += resourcesAvailable[num2].stackCount; num2++; }while (num < neededTotal && num2 < resourcesAvailable.Count); resourcesAvailable.RemoveRange(num2, resourcesAvailable.Count - num2); resourcesAvailable.Remove(foundRes); Job job = JobMaker.MakeJob(JobDefOf.HaulToContainer); job.targetA = foundRes; job.targetQueueA = new List <LocalTargetInfo>(); for (num2 = 0; num2 < resourcesAvailable.Count; num2++) { job.targetQueueA.Add(resourcesAvailable[num2]); } job.targetB = thing; if (hashSet.Count > 0) { job.targetQueueB = new List <LocalTargetInfo>(); foreach (Thing item in hashSet) { job.targetQueueB.Add(item); } } job.targetC = (Thing)c; job.count = neededTotal; job.haulMode = HaulMode.ToContainer; __result = job; return(false); } flag = true; thingDefCountClass = need; } if (flag) { JobFailReason.Is($"{MissingMaterialsTranslated}: {thingDefCountClass.thingDef.label}"); } __result = null; return(false); }
/// <summary> /// Calculates the shortest path to every other node in the network. /// The implementation uses Dijkstra's algorithm, for use in a link-state routing protocol. /// </summary> /// <returns> /// The tree, in the form of a dictionary (node => predecessor of node in shortest path to node), or (this => null). /// </returns> private IDictionary<Node, Node> CalculateShortestPaths() { var nodes = Simulator.Nodes.Values; /// Best known distance (sum of costs) from this to each node IDictionary<Node, double> dist = nodes.ToDictionary(node => node, _ => Double.PositiveInfinity); /// Predecessor of each node in shortest-paths tree IDictionary<Node, Node> previous = nodes.ToDictionary(node => node, _ => (Node)null); dist[this] = 0; /// Nodes that have yet to be processed ISet<Node> queue = new HashSet<Node>(nodes); // TODO Priority queue would be faster; replace if needed while(queue.Count > 0) { Node u = queue.MinBy(node => dist[node]); queue.Remove(u); if(dist[u] == Double.PositiveInfinity) break; // remaining nodes are inaccessible foreach(Node v in queue .Where(v => Simulator.LinksBySrcDest.ContainsKey(Tuple.Create(u, v)))) { Link uv = Simulator.LinksBySrcDest[Tuple.Create(u, v)]; // Look up link cost from our own local table, instead of statically double new_dist = dist[u] + this.known_link_costs[uv]; if(new_dist < dist[v]) { dist[v] = new_dist; previous[v] = u; // TODO for priority queue, run queue.DecreaseKey(new_dist, v) } } } return previous; }