day 20 - its a mess but it works
This commit is contained in:
parent
fe181838e8
commit
572cea8a31
1 changed files with 105 additions and 0 deletions
105
day20.py
Normal file
105
day20.py
Normal 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()
|
Loading…
Reference in a new issue