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