diff --git a/2018/07/input.txt b/2018/07/input.txt new file mode 100644 index 0000000..6acbcdd --- /dev/null +++ b/2018/07/input.txt @@ -0,0 +1,101 @@ +Step U must be finished before step A can begin. +Step F must be finished before step Z can begin. +Step B must be finished before step J can begin. +Step O must be finished before step R can begin. +Step H must be finished before step S can begin. +Step T must be finished before step R can begin. +Step L must be finished before step W can begin. +Step M must be finished before step I can begin. +Step Q must be finished before step K can begin. +Step Z must be finished before step V can begin. +Step C must be finished before step E can begin. +Step W must be finished before step I can begin. +Step K must be finished before step S can begin. +Step I must be finished before step Y can begin. +Step P must be finished before step V can begin. +Step V must be finished before step X can begin. +Step R must be finished before step E can begin. +Step N must be finished before step E can begin. +Step X must be finished before step J can begin. +Step A must be finished before step J can begin. +Step S must be finished before step G can begin. +Step J must be finished before step E can begin. +Step Y must be finished before step E can begin. +Step D must be finished before step G can begin. +Step E must be finished before step G can begin. +Step K must be finished before step N can begin. +Step B must be finished before step I can begin. +Step X must be finished before step S can begin. +Step V must be finished before step S can begin. +Step U must be finished before step L can begin. +Step N must be finished before step G can begin. +Step O must be finished before step L can begin. +Step X must be finished before step E can begin. +Step V must be finished before step E can begin. +Step Y must be finished before step G can begin. +Step A must be finished before step Y can begin. +Step M must be finished before step E can begin. +Step F must be finished before step Q can begin. +Step F must be finished before step X can begin. +Step L must be finished before step C can begin. +Step T must be finished before step L can begin. +Step B must be finished before step C can begin. +Step Q must be finished before step N can begin. +Step T must be finished before step G can begin. +Step R must be finished before step D can begin. +Step I must be finished before step A can begin. +Step B must be finished before step M can begin. +Step H must be finished before step A can begin. +Step F must be finished before step K can begin. +Step U must be finished before step F can begin. +Step R must be finished before step A can begin. +Step J must be finished before step D can begin. +Step V must be finished before step Y can begin. +Step F must be finished before step J can begin. +Step C must be finished before step K can begin. +Step M must be finished before step C can begin. +Step F must be finished before step E can begin. +Step I must be finished before step E can begin. +Step T must be finished before step A can begin. +Step J must be finished before step Y can begin. +Step R must be finished before step X can begin. +Step W must be finished before step S can begin. +Step V must be finished before step R can begin. +Step U must be finished before step V can begin. +Step C must be finished before step V can begin. +Step F must be finished before step Y can begin. +Step R must be finished before step G can begin. +Step W must be finished before step N can begin. +Step H must be finished before step N can begin. +Step H must be finished before step Y can begin. +Step B must be finished before step W can begin. +Step M must be finished before step Z can begin. +Step X must be finished before step A can begin. +Step A must be finished before step G can begin. +Step N must be finished before step A can begin. +Step H must be finished before step J can begin. +Step B must be finished before step O can begin. +Step W must be finished before step A can begin. +Step P must be finished before step N can begin. +Step Z must be finished before step G can begin. +Step W must be finished before step D can begin. +Step D must be finished before step E can begin. +Step W must be finished before step J can begin. +Step N must be finished before step D can begin. +Step C must be finished before step J can begin. +Step B must be finished before step Y can begin. +Step F must be finished before step P can begin. +Step L must be finished before step P can begin. +Step X must be finished before step G can begin. +Step R must be finished before step Y can begin. +Step K must be finished before step A can begin. +Step M must be finished before step Y can begin. +Step W must be finished before step Y can begin. +Step F must be finished before step I can begin. +Step L must be finished before step X can begin. +Step R must be finished before step J can begin. +Step V must be finished before step J can begin. +Step V must be finished before step D can begin. +Step H must be finished before step C can begin. +Step O must be finished before step G can begin. +Step P must be finished before step R can begin. diff --git a/2018/07/solve.py b/2018/07/solve.py new file mode 100644 index 0000000..9f685bc --- /dev/null +++ b/2018/07/solve.py @@ -0,0 +1,115 @@ +import re +import sys + +# PART 1 + +STEP_RE = r"Step (\S+) must be finished before step (\S+) can begin.\n" + +def load_steps(filename): + steps = {} + with open(filename, "r") as f: + for line in f: + match = re.fullmatch(STEP_RE, line) + step, before = match.groups() + steps[step] = steps.get(step, set()) | {before} + + return steps + +def reverse_steps(steps): + reverse = {} + for step, befores in steps.items(): + # Make sure that step exists in reverse + reverse[step] = reverse.get(step, set()) + + for before in befores: + reverse[before] = reverse.get(before, set()) | {step} + + return reverse + +def duration_of(step): + return ord(step) - ord("A") + 61 + +class Tree: + def __init__(self, steps, workers=1): + self.workers = {i: None for i in range(workers)} + self.steps = reverse_steps(steps) # Warning: Steps are reversed in Trees. + self.result = [] + self.duration = 0 + + def working(self): + return {worker: work for worker, work in self.workers.items() if work is not None} + + def find_free(self): + return {step for step, afters in self.steps.items() if len(afters) == 0} + + def find_working(self): + return {step for (step, _) in self.working().values()} + + def find_available(self): + return self.find_free() - self.find_working() + + def remove_step(self, step): + try: + del self.steps[step] + except KeyError: + pass + + for s in self.steps.values(): + try: + s.remove(step) + except KeyError: + pass + + def update_workers(self): + min_duration = min(duration for (_, duration) in self.working().values()) + self.duration += min_duration + + finished_steps = set() + + # Subtract min_duration from all workers + for w, s in self.workers.items(): + if s is not None: + step, duration = s + duration -= min_duration + + if duration <= 0: + finished_steps.add(step) + self.remove_step(step) + self.workers[w] = None + else: + self.workers[w] = (step, duration) + + self.result += list(finished_steps) + + def distribute_jobs(self): + available = list(reversed(sorted(self.find_available()))) + + for w, s in self.workers.items(): + if not available: + break + + if s is None: + step = available.pop() + duration = duration_of(step) + self.workers[w] = (step, duration) + + def run(self): + while self.steps: + self.distribute_jobs() + self.update_workers() + +def main(filename): + print(f"Solutions for {filename}") + steps = load_steps(filename) + tree = Tree(steps, workers=1) + tree.run() + sequence = "".join(tree.result) + print(f"Part 1: {sequence}") + tree = Tree(steps, workers=5) + tree.run() + duration = tree.duration + print(f"Part 2: {duration}") + +if __name__ == "__main__": + for filename in sys.argv[1:]: + main(filename) diff --git a/2018/07/test_input.txt b/2018/07/test_input.txt new file mode 100644 index 0000000..9ab25bf --- /dev/null +++ b/2018/07/test_input.txt @@ -0,0 +1,7 @@ +Step C must be finished before step A can begin. +Step C must be finished before step F can begin. +Step A must be finished before step B can begin. +Step A must be finished before step D can begin. +Step B must be finished before step E can begin. +Step D must be finished before step E can begin. +Step F must be finished before step E can begin.