|
- import math
-
-
- def send(parent, sender, signal):
- match kinds[sender], signal:
- case 'rx' | 'output', _:
- signal = None
- case 'button' | 'broadcaster', _:
- pass
- case '%', 0:
- signal = state[sender] = int(not state[sender])
- case '%', 1:
- signal = None
- case '&', _:
- state[sender][parent] = signal
- seen = set(state[sender].values())
- signal = 0 if seen == {1} else 1
- case default:
- raise RuntimeError(default)
-
- if signal is not None:
- for target in targets[sender]:
- # print(sender, signal, target)
- output.append(signal)
- yield (sender, target, signal)
-
-
- def deps(p):
- seen = set()
- state = {p}
- while state:
- seen |= state
- state = {k for p in state for k, vs in targets.items() if p in vs and k not in seen}
- return tuple(sorted(seen))
-
-
- text = open(0).read()
- targets = {'button': ['broadcaster']}
- kinds = {'button': 'button', 'rx': 'rx', 'output': 'output'}
- for line in text.splitlines():
- src, dst = line.split(' -> ')
- dst = dst.split(', ')
- if src == 'broadcaster':
- label = kind = 'broadcaster'
- else:
- label, kind = src[1:], src[0]
- targets[label] = dst
- kinds[label] = kind
- state = {}
- state |= {l: 0 for l, k in kinds.items() if k == '%'}
- state |= {l: {i: 0 for i, ts in targets.items() if l in ts} for l, k in kinds.items() if k == '&'}
-
- families = {}
- for k in kinds:
- families.setdefault(hash(deps(k)), []).append(k)
- families = {tuple(vs): set() for vs in families.values() if len(vs) > 1}
-
- seq = []
- seen = set()
- while True:
- output = []
- active = [(None, 'button', 0)]
- while active:
- active = [new for old in active for new in send(*old)]
- seq.append(output)
-
- before = [len(vs) for vs in families.values()]
- for ks in families:
- families[ks].add(hash(str([state[k] for k in ks])))
- after = [len(vs) for vs in families.values()]
- if before == after:
- break
-
- if len(seq) == 1000:
- # pt 1
- los = [sum(v == 0 for v in vs) for vs in seq]
- his = [sum(v == 1 for v in vs) for vs in seq]
- print(sum(los[i % len(los)] for i in range(1000)) * sum(his[i % len(his)] for i in range(1000)))
- print(math.prod(after))
|