|
| 1 | +from collections import defaultdict, deque |
| 2 | +from itertools import count |
| 3 | +from math import lcm, prod |
| 4 | + |
| 5 | +with open("input") as f: |
| 6 | + ws = [l.split() for l in f.read().strip().replace(",", "").split("\n")] |
| 7 | + |
| 8 | +flips = {w[1:] for w, *_ in ws if w[0] == "%"} |
| 9 | + |
| 10 | +parents = defaultdict(dict) |
| 11 | +children = defaultdict(list) |
| 12 | + |
| 13 | +for w, _, *regs in ws: |
| 14 | + for reg in regs: |
| 15 | + parents[reg][w.strip("&%")] = False |
| 16 | + children[w.strip("&%")].append(reg) |
| 17 | + |
| 18 | + |
| 19 | +def press_button(states, sent, periods, i): |
| 20 | + q = deque([("broadcaster", "button", False)]) |
| 21 | + |
| 22 | + def send(sender, signal): |
| 23 | + for c in children[sender]: |
| 24 | + q.append((c, sender, signal)) |
| 25 | + |
| 26 | + while q: |
| 27 | + receiver, sender, signal = q.popleft() |
| 28 | + sent[signal] += 1 |
| 29 | + if receiver == "broadcaster": |
| 30 | + send("broadcaster", signal) |
| 31 | + elif receiver in flips: |
| 32 | + if not signal: |
| 33 | + states[receiver] = not states[receiver] |
| 34 | + send(receiver, states[receiver]) |
| 35 | + else: |
| 36 | + if signal and receiver == "tg" and sender not in periods: # For part 2 |
| 37 | + periods[sender] = i |
| 38 | + parents[receiver][sender] = signal |
| 39 | + send(receiver, not all(parents[receiver].values())) |
| 40 | + return states, sent, periods |
| 41 | + |
| 42 | + |
| 43 | +# Part 1 |
| 44 | +states = defaultdict(bool) |
| 45 | +sent = defaultdict(int) |
| 46 | + |
| 47 | +for _ in range(1000): |
| 48 | + states, sent, _ = press_button(states, sent, {}, 0) |
| 49 | + |
| 50 | +print(prod(sent.values())) |
| 51 | + |
| 52 | +# Part 2 |
| 53 | +# For part 2, we manually inspect the output. We find that rx depends only on tg, |
| 54 | +# and that tg depends on four other registers. By watching the changes in those, |
| 55 | +# we find that they are cyclic, so the earliest time tg could possible be set is |
| 56 | +# at a button click count corresponding to the least common multiple of the cycle |
| 57 | +# lengths for the four other registers. |
| 58 | +states = defaultdict(bool) |
| 59 | +sent = defaultdict(int) |
| 60 | +periods = {} |
| 61 | + |
| 62 | +for i in count(1): |
| 63 | + states, _, periods = press_button(states, sent, periods, i) |
| 64 | + if len(periods) == 4: |
| 65 | + print(lcm(*periods.values())) |
| 66 | + break |
0 commit comments