diff --git a/day20.py b/day20.py new file mode 100644 index 0000000..ff5c09c --- /dev/null +++ b/day20.py @@ -0,0 +1,105 @@ +from collections import defaultdict, deque +import math +from pprint import pprint +import sys +import re + +modules = {} +conjunctions = {} +flipflops = {} + +firstit = {} +cycles = {} + +def simulate(it): + queue = deque([(None, "button", 0)]) + pulses = [0, 0] + + while queue: + (source, target, level) = queue.popleft() + if target not in modules: + continue + + (type, destinations) = modules[target] + + if type == "": + pass + elif type == "%": + if level == 1: + continue + + flipflops[target] = not flipflops[target] + level = int(flipflops[target]) + elif type == "&": + conjunction = conjunctions[target] + conjunction[source] = level + level = 0 if all(conjunction.values()) else 1 + else: + continue + + for destination in destinations: + queue.append((target, destination, level)) + pulses[level] += 1 + + if destination == "dt" and level and target not in cycles: + if target not in firstit: + firstit[target] = it + continue + + cycle = it - firstit[target] + cycles[target] = (firstit[target], cycle) + + if len(cycles) == len(conjunctions["dt"]): + lcm = math.lcm(*(v[1] for v in cycles.values())) + return (pulses, lcm) + + return (pulses, None) + +def main(): + has_rx = False + with open(sys.argv[1]) as f: + for line in f: + (type, name, destinations) = re.match(r"([%\&]?)(.+) -> (.+)", line).groups() + destinations = destinations.split(", ") + modules[name] = (type, destinations) + + if "rx" in destinations: + has_rx = True + + if type == "%": + flipflops[name] = False + elif type == "&": + conjunctions[name] = {} + + modules["button"] = ("", ["broadcaster"]) + + for (name, (type, dests)) in modules.items(): + for dest in dests: + if dest not in modules or modules[dest][0] != "&": + continue + conjunctions[dest][name] = 0 + + (lows, highs) = (0, 0) + (part1, part2) = (None, None) + it = 0 + + while part1 is None or part2 is None: + ([low, high], cycle) = simulate(it) + + if it < 1000: + lows += low + highs += high + elif it == 1000: + part1 = lows * highs + if not has_rx: + break + + if cycle: + part2 = cycle + + it += 1 + + print(part1, part2) + +if __name__ == "__main__": + main() \ No newline at end of file