from collections import defaultdict import re import string import pdb def get_first(steps): for step, deps in steps.items(): if len(deps) == 0: return step with open('data/07.txt') as f: regexp = re.compile('Step (.) must be finished before step (.) can begin.') data = [regexp.match(line).groups() for line in f] requires = {} for before, after in data: if before not in requires: requires[before] = set() if after not in requires: requires[after] = set() requires[after].add(before) workers = [] incomplete = {s: set(d) for s, d in requires.items()} complete = [] available = set() while len(incomplete): for step, deps in incomplete.items(): if len(deps) == 0: available.add(step) s = sorted(available)[0] complete.append(s) for deps in incomplete.values(): if s in deps: deps.remove(s) available.remove(s) del incomplete[s] print(f'Part 1: {"".join(complete)}\n') step_times = {c: 61 + i for i, c in enumerate(string.ascii_uppercase)} unattempted = {s: set(d) for s, d in requires.items()} complete = [] available = set() running = set() workers = [(None, 0) for i in range(5)] time = -1 while len(unattempted) or len(running): time += 1 for i, (s, t) in enumerate(workers): if s and (time - step_times[s] - t == 0): complete.append(s) running.remove(s) for deps in unattempted.values(): if s in deps: deps.remove(s) workers[i] = (None, 0) for step, deps in unattempted.items(): if len(deps) == 0: available.add(step) ordered_steps = sorted(available) for i, (s, t) in enumerate(workers): if s is None: try: new_step = ordered_steps.pop(0) workers[i] = (new_step, time) del unattempted[new_step] available.remove(new_step) running.add(new_step) except IndexError: pass print(f'Part 2: {time}\n')