From 47b0e32034db894e0116e670cefc77150952d977 Mon Sep 17 00:00:00 2001 From: Thibaud Date: Fri, 1 Aug 2025 10:30:26 +0200 Subject: [PATCH] 2019 day7 part 2 --- 2019/day7/day7.py | 61 +++++++++++++++++++++++++++++++++++------ 2019/intcode/intcode.py | 50 ++++++++++++++++++++++++--------- 2 files changed, 89 insertions(+), 22 deletions(-) diff --git a/2019/day7/day7.py b/2019/day7/day7.py index b8d6e58..73b4283 100644 --- a/2019/day7/day7.py +++ b/2019/day7/day7.py @@ -5,18 +5,23 @@ from pathlib import Path # installed module https://stackoverflow.com/a/50194143 sys.path.append(str(Path(__file__).absolute().parent.parent / "intcode")) -import itertools -from intcode import interpret_intcode +from itertools import cycle, permutations +from intcode import interpret_intcode, Interpreter def main(inp): mem = list(map(int, inp.readline().rstrip().split(","))) max_ret = 0 - for seq in itertools.permutations([0, 1, 2, 3, 4], 5): + for seq in permutations([0, 1, 2, 3, 4], 5): ret = amplifiers(mem, list(seq)) - #print(ret) max_ret = max(ret[0], max_ret) - print(max_ret) + print("Part 1: ", max_ret) + + max_ret = 0 + for seq in permutations((5, 6, 7, 8, 9)): + ret = part2(mem, list(seq)) + max_ret = max(max_ret, ret) + print("Part 2: ", max_ret) def amplifiers(program, sequence): @@ -27,27 +32,65 @@ def amplifiers(program, sequence): ret = interpret_intcode(program[::], [sequence.pop(0), ret.pop()]) return ret + +def part2(program, sequence): + amplifiers = [Interpreter(program[::], [sequence.pop(0)]) for _ in range(5)] + it = cycle(enumerate(amplifiers)) + + id_, amp = next(it) + inp = 0 + max_signal = 0 + while True: + max_signal = max(max_signal, inp) + amp.stdin.append(inp) + amp.interpret() + out = amp.stdout + if amp.halted: + break + next_id, next_amp = next(it) + inp = out.pop(0) + amp = next_amp + id_= next_id + return max_signal + + def tests(): program = [3, 15, 3, 16, 1002, 16, 10, 16, 1, 16, 15, 15, 4, 15, 99, 0, 0] sequence = [4, 3, 2, 1, 0] res = amplifiers(program, sequence) assert res == [43210] - program = [3,23,3,24,1002,24,10,24,1002,23,-1,23, 101,5,23,23,1,24,23,23,4,23,99,0,0] + program = [3,23,3,24,1002,24,10,24,1002,23,-1,23, + 101,5,23,23,1,24,23,23,4,23,99,0,0] sequence = [0,1,2,3,4] res = amplifiers(program, sequence) assert res == [54321] - program = [3,31,3,32,1002,32,10,32,1001,31,-2,31,1007,31,0,33, 1002,33,7,33,1,33,31,31,1,32,31,31,4,31,99,0,0,0] + program = [3,31,3,32,1002,32,10,32,1001,31,-2,31,1007,31,0,33, + 1002,33,7,33,1,33,31,31,1,32,31,31,4,31,99,0,0,0] sequence = [1,0,4,3,2] res = amplifiers(program, sequence) assert res == [65210] - print("All tests passed") + +def tests2(): + program = [3,26,1001,26,-4,26,3,27,1002,27,2,27,1,27,26, + 27,4,27,1001,28,-1,28,1005,28,6,99,0,0,5] + sequence = [9,8,7,6,5] + assert part2(program, sequence) == 139629729 + + + program = [3,52,1001,52,-5,52,3,53,1,52,56,54,1007,54,5,55,1005,55,26,1001,54, + -5,54,1105,1,12,1,53,54,53,1008,54,0,55,1001,55,1,55,2,53,55,53,4, + 53,1001,56,-1,56,1005,56,6,99,0,0,0,0,10] + sequence = [9,7,8,5,6] + assert part2(program, sequence) == 18216 + if __name__ == "__main__": import fileinput - main(fileinput.input()) tests() + tests2() + main(fileinput.input()) diff --git a/2019/intcode/intcode.py b/2019/intcode/intcode.py index 5c1655c..be112cb 100644 --- a/2019/intcode/intcode.py +++ b/2019/intcode/intcode.py @@ -3,7 +3,7 @@ from collections import namedtuple from enum import Enum import logging -logging.basicConfig(format="%(levelname)s:%(message)s", level=logging.DEBUG) +logging.basicConfig(format="%(levelname)s:%(message)s", level=logging.WARN) def get_nth_digit(n, number): @@ -40,6 +40,7 @@ class Instruction: self.handler = getattr(self, self.handler_name, self.handle_termination) self.input = None self.output = None + self.halted = False def __repr__(self): return f"[{self.opcode}] Instruction({self.operation}, {self.modes})" @@ -102,6 +103,7 @@ class Instruction: def handle_termination(self, program, ip): logging.debug("HALT") + self.halted = True return ip def _get_param(self, program, ip, i=0): @@ -117,16 +119,38 @@ class Instruction: return first, second -def interpret_intcode(program, stdin=[]): - ip = 0 - out = [] - while program[ip] != 99: - opcode = program[ip] - instruction = Instruction(opcode) - if instruction.operation == Operation.INPUT: - instruction.input=stdin.pop(0) - ip = instruction.handle(program, ip) - if instruction.output is not None: - out.append(instruction.output) - return out +class Interpreter: + def __init__(self, program, stdin=[]): + self.ip = 0 + self.stdin = stdin + self.stdout = [] + self.program = program + self.halted = False + + def __repr__(self): + return f"Interpreter(ip={self.ip}, {self.stdin}, {self.stdout}, {self.halted})" + + def next_instruction(self): + instruction = Instruction(self.program[self.ip]) + if instruction.operation == Operation.INPUT: + instruction.input = self.stdin.pop(0) + self.ip = instruction.handle(self.program, self.ip) + if instruction.output is not None: + self.stdout.append(instruction.output) + elif instruction.halted: + self.halted = True + return instruction + + def interpret(self, break_on_output=True): + while instruction := self.next_instruction(): + if self.halted: + break + if break_on_output and instruction.output is not None: + break + + +def interpret_intcode(program, stdin=[]): + interpreter = Interpreter(program, stdin) + interpreter.interpret(break_on_output=False) + return interpreter.stdout