From 1613813d7a3b977e08e75b03b2e6fb392a1b498f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Doblas=20Jim=C3=A9nez?= Date: Tue, 15 Mar 2022 14:33:14 +0100 Subject: [PATCH] Solution to problem 7 in Python --- src/Year_2018/P7.py | 83 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/src/Year_2018/P7.py b/src/Year_2018/P7.py index 5590b3d..587d62d 100644 --- a/src/Year_2018/P7.py +++ b/src/Year_2018/P7.py @@ -60,6 +60,8 @@ # In what order should the steps in your instructions be completed? +from string import ascii_uppercase + import networkx as nx with open("files/P7.txt") as f: @@ -76,5 +78,86 @@ def part_1() -> None: print(f"The correct order will be {order}") +# --- Part Two --- + +# As you're about to begin construction, four of the Elves offer to help. "The +# sun will set soon; it'll go faster if we work together." Now, you need to +# account for multiple people working on steps simultaneously. If multiple +# steps are available, workers should still begin them in alphabetical order. + +# Each step takes 60 seconds plus an amount corresponding to its letter: A=1, +# B=2, C=3, and so on. So, step A takes 60+1=61 seconds, while step Z takes +# 60+26=86 seconds. No time is required between steps. + +# To simplify things for the example, however, suppose you only have help from +# one Elf (a total of two workers) and that each step takes 60 fewer seconds +# (so that step A takes 1 second and step Z takes 26 seconds). Then, using the +# same instructions as above, this is how each second would be spent: + +# Second Worker 1 Worker 2 Done +# 0 C . +# 1 C . +# 2 C . +# 3 A F C +# 4 B F CA +# 5 B F CA +# 6 D F CAB +# 7 D F CAB +# 8 D F CAB +# 9 D . CABF +# 10 E . CABFD +# 11 E . CABFD +# 12 E . CABFD +# 13 E . CABFD +# 14 E . CABFD +# 15 . . CABFDE + +# Each row represents one second of time. The Second column identifies how many +# seconds have passed as of the beginning of that second. Each worker column +# shows the step that worker is currently doing (or . if they are idle). The +# Done column shows completed steps. + +# Note that the order of the steps has changed; this is because steps now take +# time to finish and multiple workers can begin multiple steps simultaneously. + +# In this example, it would take 15 seconds for two workers to complete these +# steps. + +# With 5 workers and the 60+ second step durations described above, how long +# will it take to complete all of the steps? + + +def part_2() -> None: + G = nx.DiGraph() + for step in steps: + parent, child = step[5:6], step[36:37] + G.add_edge(parent, child) + + n_workers = 5 + + # Add amount of work for each node + for node in G.nodes: + G.nodes[node]["work"] = 61 + ord(node) - ord("A") + + time = 0 + while G.nodes: + # Find nodes available for work + available_nodes = [node for node in G.nodes if G.in_degree(node) == 0] + # Sort available nodes: Work on nodes with least remaining work + available_nodes.sort(key=lambda node: G.nodes[node]["work"]) + + # Reduce remaining work for n_workers of the available nodes + for worker, node in zip(range(n_workers), available_nodes): + G.nodes[node]["work"] -= 1 + # Remove finished nodes + if G.nodes[node]["work"] == 0: + G.remove_node(node) + + time += 1 + + print(f"Finishing all the work took {time} seconds") + + if __name__ == "__main__": part_1() + part_2()