diff --git a/day05.py b/day05.py index 8846d57..9e19e18 100644 --- a/day05.py +++ b/day05.py @@ -9,16 +9,18 @@ class Day(AOCDay): def part1(self) -> Any: comp = IntCode(self.getInputAsArraySplit(",", int)) - comp.input.put(1) - comp.run() + comp.addInput(1) + comp.start() while True: - if (check := comp.output.get()) != 0: + if (check := comp.getOutput()) != 0: + comp.join() return check def part2(self) -> Any: comp = IntCode(self.getInputAsArraySplit(",", int)) - comp.input.put(5) - comp.run() + comp.addInput(5) + comp.start() while True: - if (check := comp.output.get()) != 0: + if (check := comp.getOutput()) != 0: + comp.join() return check diff --git a/day07.py b/day07.py new file mode 100644 index 0000000..bc14a1d --- /dev/null +++ b/day07.py @@ -0,0 +1,72 @@ +import itertools + +from aoc import AOCDay + +from intcode import IntCode +from typing import Any, List + + +def get_comps(memory: List[int]) -> List[IntCode]: + comps = [] + for _ in range(5): + comps.append(IntCode(memory.copy())) + + return comps + + +class Day(AOCDay): + test_solutions_p1 = [43210, 54321, 65210] + test_solutions_p2 = [139629729, 18216] + + def part1(self) -> Any: + init_memory = self.getInputAsArraySplit(",", int) + max_signal = 0 + phase_settings = [0, 1, 2, 3, 4] + for s in itertools.permutations(phase_settings): + comps = get_comps(init_memory) + for i, input1 in enumerate(s): + if i == 0: + input2 = 0 + else: + input2 = comps[i-1].getOutput() + + comps[i].addInput(input1) + comps[i].addInput(input2) + comps[i].run() + + signal = comps[4].getOutput() + if signal > max_signal: + max_signal = signal + + return max_signal + + def part2(self) -> Any: + init_memory = self.getInputAsArraySplit(",", int) + max_signal = 0 + phase_settings = [5, 6, 7, 8, 9] + for s in itertools.permutations(phase_settings): + comps = get_comps(init_memory.copy()) + + for i, input1 in enumerate(s): + if i == 0 and not comps[i].isRunning(): + input2 = 0 + else: + input2 = comps[i-1].getOutput() + + comps[i].addInput(input1) + comps[i].addInput(input2) + comps[i].start() + + while not comps[4].isHalted(): + for i in range(5): + if not comps[i].isHalted() and not comps[i-1].isHalted(): + comps[i].addInput(comps[i-1].getOutput()) + + signal = comps[4].getOutput() + if signal > max_signal: + max_signal = signal + + for i in range(5): + comps[i].join() + + return max_signal diff --git a/inputs/input07 b/inputs/input07 new file mode 100644 index 0000000..3ab6c2d --- /dev/null +++ b/inputs/input07 @@ -0,0 +1 @@ +3,8,1001,8,10,8,105,1,0,0,21,38,59,76,89,106,187,268,349,430,99999,3,9,1002,9,3,9,101,2,9,9,1002,9,4,9,4,9,99,3,9,1001,9,5,9,1002,9,5,9,1001,9,2,9,1002,9,3,9,4,9,99,3,9,1001,9,4,9,102,4,9,9,1001,9,3,9,4,9,99,3,9,101,4,9,9,1002,9,5,9,4,9,99,3,9,1002,9,3,9,101,5,9,9,1002,9,3,9,4,9,99,3,9,102,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,101,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,101,1,9,9,4,9,3,9,1001,9,1,9,4,9,3,9,1002,9,2,9,4,9,3,9,101,2,9,9,4,9,99,3,9,1002,9,2,9,4,9,3,9,101,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,101,1,9,9,4,9,3,9,102,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,101,2,9,9,4,9,3,9,101,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,2,9,4,9,99,3,9,1002,9,2,9,4,9,3,9,1001,9,2,9,4,9,3,9,101,1,9,9,4,9,3,9,101,2,9,9,4,9,3,9,101,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,1,9,4,9,3,9,1001,9,2,9,4,9,99,3,9,1001,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,101,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,101,1,9,9,4,9,3,9,101,1,9,9,4,9,99,3,9,101,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,1001,9,2,9,4,9,3,9,1001,9,2,9,4,9,3,9,1001,9,2,9,4,9,3,9,1001,9,1,9,4,9,3,9,1001,9,2,9,4,9,3,9,1001,9,2,9,4,9,3,9,102,2,9,9,4,9,99 diff --git a/inputs/test_input07_1_0 b/inputs/test_input07_1_0 new file mode 100644 index 0000000..e626457 --- /dev/null +++ b/inputs/test_input07_1_0 @@ -0,0 +1 @@ +3,15,3,16,1002,16,10,16,1,16,15,15,4,15,99,0,0 diff --git a/inputs/test_input07_1_1 b/inputs/test_input07_1_1 new file mode 100644 index 0000000..e797139 --- /dev/null +++ b/inputs/test_input07_1_1 @@ -0,0 +1 @@ +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 diff --git a/inputs/test_input07_1_2 b/inputs/test_input07_1_2 new file mode 100644 index 0000000..2beb112 --- /dev/null +++ b/inputs/test_input07_1_2 @@ -0,0 +1 @@ +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 diff --git a/inputs/test_input07_2_0 b/inputs/test_input07_2_0 new file mode 100644 index 0000000..ad78133 --- /dev/null +++ b/inputs/test_input07_2_0 @@ -0,0 +1 @@ +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 diff --git a/inputs/test_input07_2_1 b/inputs/test_input07_2_1 new file mode 100644 index 0000000..cd43fb9 --- /dev/null +++ b/inputs/test_input07_2_1 @@ -0,0 +1 @@ +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 diff --git a/intcode.py b/intcode.py index 19f688c..2debc37 100644 --- a/intcode.py +++ b/intcode.py @@ -1,14 +1,23 @@ -from typing import List +from enum import Enum from queue import Queue +import threading +from typing import List, Union -class IntCode: +class IntCodeState(Enum): + INITIALIZED = 0 + RUNNING = 1 + HALTED = 2 + + +class IntCode(threading.Thread): def __init__(self, memory: List[int], mem_size: int = 0): + super().__init__() self.instr_ptr = 0 - self.halted = False self.memory = memory - self.input = Queue() - self.output = Queue() + self.input_queue = Queue() + self.output_queue = Queue() + self.state = IntCodeState.INITIALIZED if len(self.memory) < mem_size: self.memory.extend([0] * (mem_size - len(self.memory))) @@ -18,8 +27,33 @@ class IntCode: elif mode == 1: return self.memory[address] + def isRunning(self): + return self.state == IntCodeState.RUNNING + + def isHalted(self): + return self.state == IntCodeState.HALTED + + def sendOutputTo(self, target_queue: Queue): + self.output_queue = target_queue + + def addInput(self, value: int): + self.input_queue.put(value) + + def getOutput(self, count: int = 1, block: bool = True, timeout: int = None) -> Union[int, List[int]]: + if count == 1: + res = self.output_queue.get(block=block, timeout=timeout) + self.output_queue.task_done() + else: + res = [] + for _ in range(count): + res.append(self.output_queue.get(block=block, timeout=timeout)) + self.output_queue.task_done() + + return res + def run(self): - while not self.halted: + self.state = IntCodeState.RUNNING + while not self.isHalted(): instr = self.memory[self.instr_ptr] % 100 p1_mode = self.memory[self.instr_ptr] // 100 % 10 p2_mode = self.memory[self.instr_ptr] // 1_000 % 10 @@ -38,11 +72,12 @@ class IntCode: self.memory[target_addr] = param1 * param2 self.instr_ptr += 4 elif instr == 3: # input - target_addr = self.memory[self.instr_ptr + 3] - self.memory[target_addr] = self.input.get() + target_addr = self.memory[self.instr_ptr + 1] + self.memory[target_addr] = self.input_queue.get() + self.input_queue.task_done() self.instr_ptr += 2 elif instr == 4: # output - self.output.put(self.get_parameter_value(self.instr_ptr + 1, p1_mode)) + self.output_queue.put(self.get_parameter_value(self.instr_ptr + 1, p1_mode)) self.instr_ptr += 2 elif instr == 5: # jump-if-true if self.get_parameter_value(self.instr_ptr + 1, p1_mode) != 0: @@ -67,6 +102,7 @@ class IntCode: self.memory[target_addr] = param1 == param2 self.instr_ptr += 4 elif instr == 99: - self.halted = True + self.state = IntCodeState.HALTED + return else: raise ValueError("Invalid instruction encountered at pos %d: %d" % (self.instr_ptr, instr))