day 20 - its a mess but it works

This commit is contained in:
Sijmen 2024-01-04 05:56:24 +01:00
parent fe181838e8
commit 572cea8a31
Signed by: vijfhoek
GPG Key ID: DAF7821E067D9C48
1 changed files with 105 additions and 0 deletions

105
day20.py Normal file
View File

@ -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()