Add 2023 day 20
This commit is contained in:
parent
f47445775d
commit
f97b0b70df
157
2023/day20.py
Executable file
157
2023/day20.py
Executable file
@ -0,0 +1,157 @@
|
||||
#!/usr/bin/python3
|
||||
"""
|
||||
Jour 20 du défi Advent Of Code pour l'année 2023
|
||||
"""
|
||||
import os
|
||||
import heapq
|
||||
import math
|
||||
|
||||
FLIP_FLOP=0
|
||||
BROADCAST=1
|
||||
CONJUNCTION=2
|
||||
|
||||
class Module:
|
||||
def __init__(self, text, inputs = None):
|
||||
self.status = {}
|
||||
self.dest = text.split(" -> ")[1].strip().split(", ")
|
||||
if inputs is not None:
|
||||
self.inputs = inputs
|
||||
else:
|
||||
self.inputs = []
|
||||
|
||||
match (text[0]):
|
||||
case '%':
|
||||
self.type = FLIP_FLOP
|
||||
self.status["flip-flopped"] = False
|
||||
case '&':
|
||||
self.type = CONJUNCTION
|
||||
self.status["received"] = {i: "-low" for i in self.inputs}
|
||||
case 'b':
|
||||
self.type = BROADCAST
|
||||
|
||||
if self.type == BROADCAST:
|
||||
self.name = "broadcaster"
|
||||
else:
|
||||
self.name = text.split(" -> ")[0][1:]
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
if self.type == BROADCAST:
|
||||
return f"{self.name} -> {''.join(self.dest)}"
|
||||
if self.type == CONJUNCTION:
|
||||
return f"&{self.name} -> {''.join(self.dest)} [{self.status['received']}]"
|
||||
if self.type == FLIP_FLOP:
|
||||
return f"%{self.name} -> {''.join(self.dest)}"
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def get_signals(self, signal):
|
||||
if self.type == FLIP_FLOP:
|
||||
if signal[1] == "-high":
|
||||
return []
|
||||
if self.status["flip-flopped"]: # Is on ?
|
||||
next = "-low"
|
||||
else:
|
||||
next = "-high"
|
||||
self.status["flip-flopped"] = not self.status["flip-flopped"]
|
||||
return [(dest, next) for dest in self.dest]
|
||||
|
||||
if self.type == CONJUNCTION:
|
||||
self.status["received"][signal[2]] = signal[1]
|
||||
#print({i for i in self.status["received"].values()}, self.status["received"])
|
||||
if "-low" not in {i for i in self.status["received"].values()}:
|
||||
return [(dest, "-low") for dest in self.dest]
|
||||
return [(dest, "-high") for dest in self.dest]
|
||||
|
||||
if self.type == BROADCAST:
|
||||
return [(dest, signal[1]) for dest in self.dest]
|
||||
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
|
||||
|
||||
def read_sample():
|
||||
"""récupère les entrées depuis le fichier texte correspondant"""
|
||||
filename = os.path.join(os.path.dirname(__file__ ), "inputs", "day20.txt")
|
||||
with open(filename, 'r') as f:
|
||||
sample = f.read().split('\n')
|
||||
sample = [ i for i in sample if i != '' ]
|
||||
return sample
|
||||
|
||||
def propagate(modules, signal=("broadcaster", "-low")):
|
||||
low_pulses, high_pulses = 0, 0
|
||||
priority_queue = [(0, (signal[0], signal[1], "button"))]
|
||||
while priority_queue:
|
||||
dist, signal = heapq.heappop(priority_queue)
|
||||
if signal[1] == "-low":
|
||||
low_pulses += 1
|
||||
else:
|
||||
high_pulses += 1
|
||||
|
||||
if signal[0] in modules.keys():
|
||||
next_messages = modules[signal[0]].get_signals(signal)
|
||||
for message in next_messages:
|
||||
#print(f"{signal[0]} received {signal[1]}: {message[1]} -> {message[0]}")
|
||||
msg = (message[0], message[1], signal[0])
|
||||
heapq.heappush(priority_queue, (dist+1, msg))
|
||||
elif signal[1] == "-low":
|
||||
return low_pulses, high_pulses, True
|
||||
|
||||
return low_pulses, high_pulses, False
|
||||
|
||||
|
||||
def get_modules(sample):
|
||||
modules = { i.name: Module(i) for i in sample }
|
||||
|
||||
for m in modules.values():
|
||||
for d in m.dest:
|
||||
if d in modules.keys():
|
||||
modules[d].inputs.append(m.name)
|
||||
if modules[d].type == CONJUNCTION:
|
||||
modules[d].status["received"][m.name] = "-low"
|
||||
return modules
|
||||
|
||||
|
||||
def part1(sample, times=1000):
|
||||
"""Partie 1 du défi"""
|
||||
modules = get_modules(sample)
|
||||
|
||||
#print(modules)
|
||||
somme = (0, 0)
|
||||
for i in range(times):
|
||||
res = propagate(modules)
|
||||
somme = (somme[0]+res[0], somme[1]+res[1])
|
||||
return somme[0]*somme[1], somme
|
||||
|
||||
|
||||
def part2(sample):
|
||||
"""Partie 1 du défi"""
|
||||
modules = get_modules(sample)
|
||||
|
||||
min_high = {}
|
||||
pre = [m for m in modules if "rx" in m.dest][0]
|
||||
for key in pre.status["received"].keys():
|
||||
min_high[key] = -1
|
||||
|
||||
#print(modules)
|
||||
activations = 0
|
||||
while True:
|
||||
activations+=1
|
||||
res = propagate(modules)
|
||||
pre = [m for m in modules if "rx" in m.dest][0]
|
||||
for key in pre.status["received"].keys():
|
||||
if pre.status["received"]["key"] == "-high" and min_high[key] == -1:
|
||||
min_high[key] = activations
|
||||
|
||||
if -1 not in min_high.values():
|
||||
return math.lcm(*min_high.values())
|
||||
|
||||
|
||||
def main():
|
||||
"""Fonction principale"""
|
||||
print(f"part1: {part1(read_sample())}")
|
||||
print(f"part2: {part2(read_sample())}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Loading…
Reference in New Issue
Block a user