├── src ├── hello.py ├── ops2.py ├── ops5.py ├── ops7.py ├── quiz2.py ├── day2.py ├── quiz7.py ├── quiz7_2.py ├── quiz5.py ├── quiz5_2.py ├── day5.py ├── day7.py └── day7_2.py ├── tests ├── test_hello.py ├── test_day2.py ├── test_day5.py └── test_day7.py ├── Pipfile ├── README.md └── Pipfile.lock /src/hello.py: -------------------------------------------------------------------------------- 1 | def give5(): 2 | return 5 3 | -------------------------------------------------------------------------------- /tests/test_hello.py: -------------------------------------------------------------------------------- 1 | import src.hello 2 | 3 | def test_hello(): 4 | assert(src.hello.give5() == 5) 5 | -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | name = "pypi" 3 | url = "https://pypi.org/simple" 4 | verify_ssl = true 5 | 6 | [dev-packages] 7 | 8 | [packages] 9 | pytest = "*" 10 | 11 | [requires] 12 | python_version = "3.7" 13 | -------------------------------------------------------------------------------- /src/ops2.py: -------------------------------------------------------------------------------- 1 | class HaltException(Exception): 2 | pass 3 | 4 | class InvalidOpException(Exception): 5 | pass 6 | 7 | def plus(a, b): 8 | return a + b 9 | 10 | def mult(a, b): 11 | return a * b 12 | 13 | def halt(): # Dummy function 14 | pass 15 | 16 | HALT_CODE = 99 17 | 18 | ops = {1 : plus, 19 | 2 : mult, 20 | 99: halt} 21 | 22 | -------------------------------------------------------------------------------- /src/ops5.py: -------------------------------------------------------------------------------- 1 | class HaltException(Exception): 2 | pass 3 | 4 | class InvalidOpException(Exception): 5 | pass 6 | 7 | HALT_CODE = 99 8 | 9 | OPS_NUM_ARGS = {1 : 3, 10 | 2 : 3, 11 | 3 : 1, 12 | 4 : 1, 13 | 5 : 2, 14 | 6 : 2, 15 | 7 : 3, 16 | 8 : 3} 17 | 18 | def add(a, b): 19 | return a + b 20 | 21 | def mult(a, b): 22 | return a * b 23 | 24 | def neq_zero(a, b, c): 25 | if a != 0: 26 | return b 27 | return c 28 | 29 | def eq_zero(a, b, c): 30 | if a == 0: 31 | return b 32 | return c 33 | 34 | def lt(a, b): 35 | return int(a < b) 36 | 37 | def eq(a, b): 38 | return int(a == b) 39 | 40 | -------------------------------------------------------------------------------- /src/ops7.py: -------------------------------------------------------------------------------- 1 | class HaltException(Exception): 2 | pass 3 | 4 | class InvalidOpException(Exception): 5 | pass 6 | 7 | class InvalidParameterModeException(Exception): 8 | pass 9 | 10 | HALT_CODE = 99 11 | 12 | OPS_NUM_ARGS = {1 : 3, 13 | 2 : 3, 14 | 3 : 1, 15 | 4 : 1, 16 | 5 : 2, 17 | 6 : 2, 18 | 7 : 3, 19 | 8 : 3} 20 | 21 | def add(a, b): 22 | return a + b 23 | 24 | def mult(a, b): 25 | return a * b 26 | 27 | def neq_zero(a, b, c): 28 | if a != 0: 29 | return b 30 | return c 31 | 32 | def eq_zero(a, b, c): 33 | if a == 0: 34 | return b 35 | return c 36 | 37 | def lt(a, b): 38 | return int(a < b) 39 | 40 | def eq(a, b): 41 | return int(a == b) 42 | 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Code Refactoring IAP 2020 2 | 3 | This repository contains (will contain) code for Advent of Code 2019, as part of the Code Refactoring 2020 IAP (Independent Activity Period) programme at the Singapore University of Technology and Design. 4 | 5 | The course aims to teach participants how to write readable, understandable and modifiable code, based on concepts like DRY, SRP and TDD. 6 | 7 | The course will use questions from the Advent of Code 2019 as practise questions. 8 | 9 | ### Installation 10 | Install [pipenv](https://pipenv.kennethreitz.org/en/latest/install) and [pyenv](https://github.com/pyenv/pyenv-installer). 11 | 12 | Once you have `pipenv` and `pyenv` in your `PATH`, run the following command in this repository to install the virtual environment. 13 | If prompted to install Cython3.7.1 using `pyenv`, press `` (yes). 14 | 15 | To check that it is working, first activate the virtual environment with `pipenv shell`. 16 | Then run `python -m pytest` in this directory. 17 | 18 | -------------------------------------------------------------------------------- /src/quiz2.py: -------------------------------------------------------------------------------- 1 | from copy import copy 2 | from day2 import IntcodeComputer 3 | 4 | if __name__ == '__main__': 5 | instructions = [1,12,2,3,1,1,2,3,1,3,4,3,1,5,0,3,2,6,1,19,2,19,13,23,1,23,10,27,1,13,27,31,2,31,10,35,1,35,9,39,1,39,13,43,1,13,43,47,1,47,13,51,1,13,51,55,1,5,55,59,2,10,59,63,1,9,63,67,1,6,67,71,2,71,13,75,2,75,13,79,1,79,9,83,2,83,10,87,1,9,87,91,1,6,91,95,1,95,10,99,1,99,13,103,1,13,103,107,2,13,107,111,1,111,9,115,2,115,10,119,1,119,5,123,1,123,2,127,1,127,5,0,99,2,14,0,0] 6 | instr = copy(instructions) 7 | icc = IntcodeComputer(instr) 8 | mem = icc.run() 9 | print(mem[0]) 10 | 11 | TARGET = 19690720 12 | stop_flag = False 13 | for noun in range(100): 14 | for verb in range(100): 15 | instr = copy(instructions) 16 | instr[1] = noun 17 | instr[2] = verb 18 | icc = IntcodeComputer(instr) 19 | mem = icc.run() 20 | if mem[0] == TARGET: 21 | ans = 100 * noun + verb 22 | stop_flag = True 23 | break 24 | if stop_flag: 25 | break 26 | 27 | print(ans) 28 | 29 | -------------------------------------------------------------------------------- /src/day2.py: -------------------------------------------------------------------------------- 1 | try: 2 | from src.ops2 import * 3 | except: 4 | from ops2 import * 5 | 6 | class IntcodeComputer: 7 | def __init__(self, instructions): 8 | self.memory = instructions 9 | 10 | def run(self): 11 | num_instructions = len(self.memory) // 4 12 | for i in range(num_instructions): 13 | start = i * 4 14 | end = (i+1) * 4 15 | instruction = self.memory[start:end] 16 | try: 17 | self.exec(instruction) 18 | except HaltException: 19 | break 20 | return self.memory 21 | 22 | def exec(self, instruction): 23 | op = instruction[0] 24 | if op in ops.keys(): 25 | if op == HALT_CODE: 26 | raise HaltException 27 | arg1_loc, arg2_loc, out_loc = instruction[1:] 28 | arg1, arg2 = map(self.mem_load, (arg1_loc, arg2_loc)) 29 | operation = ops[op] 30 | out = operation(arg1, arg2) 31 | else: 32 | raise InvalidOpException 33 | self.mem_store(out_loc, out) 34 | 35 | def mem_load(self, mem_loc): 36 | return self.memory[mem_loc] 37 | 38 | def mem_store(self, mem_loc, value): 39 | self.memory[mem_loc] = value 40 | 41 | -------------------------------------------------------------------------------- /tests/test_day2.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from src.day2 import IntcodeComputer, InvalidOpException 3 | 4 | def test_add(): 5 | instructions = [1, 4, 3, 3, 6 | 99] 7 | expected = [1, 4, 3, 102, 8 | 99] 9 | actual_eq_expected(instructions, expected) 10 | 11 | def test_mult(): 12 | instructions = [2, 2, 3, 3, 13 | 99] 14 | expected = [2, 2, 3, 9, 15 | 99] 16 | actual_eq_expected(instructions, expected) 17 | 18 | def test_multiple_instructions(): 19 | instructions = [1, 9, 10, 3, 20 | 2, 3, 11, 0, 21 | 99, 22 | 30, 40, 50] 23 | expected = [3500, 9, 10, 70, 24 | 2, 3, 11, 0, 25 | 99, 26 | 30, 40, 50] 27 | actual_eq_expected(instructions, expected) 28 | instructions = [1,1,1,4, 29 | 99, 30 | 5,6,0, 31 | 99] 32 | expected = [30,1,1,4, 33 | 2,5,6,0, 34 | 99] 35 | actual_eq_expected(instructions, expected) 36 | 37 | @pytest.mark.xfail(raises=InvalidOpException) 38 | def test_fail(): 39 | instructions = [0, 0, 0, 0] 40 | run_instructions(instructions) 41 | 42 | def actual_eq_expected(instructions, expected): 43 | actual = run_instructions(instructions) 44 | assert(actual == expected) 45 | 46 | def run_instructions(instructions): 47 | icc = IntcodeComputer(instructions) 48 | return icc.run() 49 | 50 | -------------------------------------------------------------------------------- /src/quiz7.py: -------------------------------------------------------------------------------- 1 | from day7 import AmplifierCircuit 2 | 3 | if __name__ == '__main__': 4 | instructions = [3,8,1001,8,10,8,105,1,0,0,21,46,63,76,97,118,199,280,361,442,99999,3,9,102,4,9,9,101,2,9,9,1002,9,5,9,101,4,9,9,102,2,9,9,4,9,99,3,9,101,5,9,9,102,3,9,9,101,3,9,9,4,9,99,3,9,1001,9,2,9,102,3,9,9,4,9,99,3,9,1002,9,5,9,101,4,9,9,1002,9,3,9,101,2,9,9,4,9,99,3,9,1002,9,5,9,101,3,9,9,1002,9,5,9,1001,9,5,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,1001,9,1,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,1001,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,102,2,9,9,4,9,99,3,9,1002,9,2,9,4,9,3,9,101,2,9,9,4,9,3,9,1001,9,1,9,4,9,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,1002,9,2,9,4,9,3,9,101,2,9,9,4,9,3,9,1001,9,1,9,4,9,3,9,102,2,9,9,4,9,99,3,9,102,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,102,2,9,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,102,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,101,1,9,9,4,9,99,3,9,1002,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,101,1,9,9,4,9,3,9,1001,9,1,9,4,9,3,9,1001,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,101,2,9,9,4,9,99,3,9,101,1,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,102,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,101,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,99] 5 | amp = AmplifierCircuit(5, instructions) 6 | max_thrust, max_setting = amp.get_max_thruster_setting() 7 | print(max_thrust) 8 | 9 | -------------------------------------------------------------------------------- /src/quiz7_2.py: -------------------------------------------------------------------------------- 1 | from day7_2 import AmplifierCircuit 2 | 3 | if __name__ == '__main__': 4 | instructions = [3,8,1001,8,10,8,105,1,0,0,21,46,63,76,97,118,199,280,361,442,99999,3,9,102,4,9,9,101,2,9,9,1002,9,5,9,101,4,9,9,102,2,9,9,4,9,99,3,9,101,5,9,9,102,3,9,9,101,3,9,9,4,9,99,3,9,1001,9,2,9,102,3,9,9,4,9,99,3,9,1002,9,5,9,101,4,9,9,1002,9,3,9,101,2,9,9,4,9,99,3,9,1002,9,5,9,101,3,9,9,1002,9,5,9,1001,9,5,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,1001,9,1,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,1001,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,102,2,9,9,4,9,99,3,9,1002,9,2,9,4,9,3,9,101,2,9,9,4,9,3,9,1001,9,1,9,4,9,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,1002,9,2,9,4,9,3,9,101,2,9,9,4,9,3,9,1001,9,1,9,4,9,3,9,102,2,9,9,4,9,99,3,9,102,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,102,2,9,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,102,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,101,1,9,9,4,9,99,3,9,1002,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,101,1,9,9,4,9,3,9,1001,9,1,9,4,9,3,9,1001,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,101,2,9,9,4,9,99,3,9,101,1,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,102,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,101,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,99] 5 | amp = AmplifierCircuit(5, instructions) 6 | max_thrust, max_setting = amp.get_max_thruster_setting(amp.run_sequentially) 7 | print(max_thrust) 8 | 9 | #instructions = [3,26,1001,26,-4,26,3,27,1002,27,2,27,1,27,26, 10 | # 27,4,27,1001,28,-1,28,1005,28,6,99,0,0,5] 11 | amp = AmplifierCircuit(5, instructions, start_settings=5) 12 | max_thrust, max_setting = amp.get_max_thruster_setting(amp.run_loop) 13 | print(max_thrust) 14 | 15 | -------------------------------------------------------------------------------- /src/quiz5.py: -------------------------------------------------------------------------------- 1 | from day5 import IntcodeComputer 2 | 3 | if __name__ == '__main__': 4 | instructions = [3,225,1,225,6,6,1100,1,238,225,104,0,1102,83,20,225,1102,55,83,224,1001,224,-4565,224,4,224,102,8,223,223,101,5,224,224,1,223,224,223,1101,52,15,225,1102,42,92,225,1101,24,65,225,101,33,44,224,101,-125,224,224,4,224,102,8,223,223,1001,224,7,224,1,223,224,223,1001,39,75,224,101,-127,224,224,4,224,1002,223,8,223,1001,224,3,224,1,223,224,223,2,14,48,224,101,-1300,224,224,4,224,1002,223,8,223,1001,224,2,224,1,223,224,223,1002,139,79,224,101,-1896,224,224,4,224,102,8,223,223,1001,224,2,224,1,223,224,223,1102,24,92,225,1101,20,53,224,101,-73,224,224,4,224,102,8,223,223,101,5,224,224,1,223,224,223,1101,70,33,225,1101,56,33,225,1,196,170,224,1001,224,-38,224,4,224,102,8,223,223,101,4,224,224,1,224,223,223,1101,50,5,225,102,91,166,224,1001,224,-3003,224,4,224,102,8,223,223,101,2,224,224,1,224,223,223,4,223,99,0,0,0,677,0,0,0,0,0,0,0,0,0,0,0,1105,0,99999,1105,227,247,1105,1,99999,1005,227,99999,1005,0,256,1105,1,99999,1106,227,99999,1106,0,265,1105,1,99999,1006,0,99999,1006,227,274,1105,1,99999,1105,1,280,1105,1,99999,1,225,225,225,1101,294,0,0,105,1,0,1105,1,99999,1106,0,300,1105,1,99999,1,225,225,225,1101,314,0,0,106,0,0,1105,1,99999,1107,677,677,224,1002,223,2,223,1006,224,329,1001,223,1,223,1107,226,677,224,102,2,223,223,1005,224,344,101,1,223,223,108,677,677,224,1002,223,2,223,1006,224,359,101,1,223,223,107,677,677,224,1002,223,2,223,1006,224,374,1001,223,1,223,1007,677,677,224,102,2,223,223,1006,224,389,101,1,223,223,108,677,226,224,102,2,223,223,1006,224,404,101,1,223,223,1108,226,677,224,102,2,223,223,1005,224,419,1001,223,1,223,7,677,226,224,102,2,223,223,1005,224,434,101,1,223,223,1008,677,677,224,102,2,223,223,1006,224,449,1001,223,1,223,1007,677,226,224,1002,223,2,223,1006,224,464,101,1,223,223,1108,677,677,224,1002,223,2,223,1005,224,479,1001,223,1,223,107,226,226,224,1002,223,2,223,1005,224,494,101,1,223,223,8,226,677,224,102,2,223,223,1006,224,509,101,1,223,223,8,677,677,224,102,2,223,223,1006,224,524,101,1,223,223,1007,226,226,224,1002,223,2,223,1006,224,539,1001,223,1,223,107,677,226,224,102,2,223,223,1006,224,554,101,1,223,223,1107,677,226,224,1002,223,2,223,1006,224,569,1001,223,1,223,1008,226,677,224,102,2,223,223,1006,224,584,1001,223,1,223,1008,226,226,224,1002,223,2,223,1005,224,599,1001,223,1,223,7,677,677,224,1002,223,2,223,1005,224,614,1001,223,1,223,1108,677,226,224,1002,223,2,223,1005,224,629,101,1,223,223,7,226,677,224,1002,223,2,223,1005,224,644,1001,223,1,223,8,677,226,224,102,2,223,223,1005,224,659,101,1,223,223,108,226,226,224,102,2,223,223,1005,224,674,101,1,223,223,4,223,99,226] 5 | icc = IntcodeComputer(instructions) 6 | icc.run(inp=(1,)) 7 | print(icc.out) 8 | -------------------------------------------------------------------------------- /src/quiz5_2.py: -------------------------------------------------------------------------------- 1 | from day5 import IntcodeComputer 2 | 3 | if __name__ == '__main__': 4 | instructions = [3,225,1,225,6,6,1100,1,238,225,104,0,1102,83,20,225,1102,55,83,224,1001,224,-4565,224,4,224,102,8,223,223,101,5,224,224,1,223,224,223,1101,52,15,225,1102,42,92,225,1101,24,65,225,101,33,44,224,101,-125,224,224,4,224,102,8,223,223,1001,224,7,224,1,223,224,223,1001,39,75,224,101,-127,224,224,4,224,1002,223,8,223,1001,224,3,224,1,223,224,223,2,14,48,224,101,-1300,224,224,4,224,1002,223,8,223,1001,224,2,224,1,223,224,223,1002,139,79,224,101,-1896,224,224,4,224,102,8,223,223,1001,224,2,224,1,223,224,223,1102,24,92,225,1101,20,53,224,101,-73,224,224,4,224,102,8,223,223,101,5,224,224,1,223,224,223,1101,70,33,225,1101,56,33,225,1,196,170,224,1001,224,-38,224,4,224,102,8,223,223,101,4,224,224,1,224,223,223,1101,50,5,225,102,91,166,224,1001,224,-3003,224,4,224,102,8,223,223,101,2,224,224,1,224,223,223,4,223,99,0,0,0,677,0,0,0,0,0,0,0,0,0,0,0,1105,0,99999,1105,227,247,1105,1,99999,1005,227,99999,1005,0,256,1105,1,99999,1106,227,99999,1106,0,265,1105,1,99999,1006,0,99999,1006,227,274,1105,1,99999,1105,1,280,1105,1,99999,1,225,225,225,1101,294,0,0,105,1,0,1105,1,99999,1106,0,300,1105,1,99999,1,225,225,225,1101,314,0,0,106,0,0,1105,1,99999,1107,677,677,224,1002,223,2,223,1006,224,329,1001,223,1,223,1107,226,677,224,102,2,223,223,1005,224,344,101,1,223,223,108,677,677,224,1002,223,2,223,1006,224,359,101,1,223,223,107,677,677,224,1002,223,2,223,1006,224,374,1001,223,1,223,1007,677,677,224,102,2,223,223,1006,224,389,101,1,223,223,108,677,226,224,102,2,223,223,1006,224,404,101,1,223,223,1108,226,677,224,102,2,223,223,1005,224,419,1001,223,1,223,7,677,226,224,102,2,223,223,1005,224,434,101,1,223,223,1008,677,677,224,102,2,223,223,1006,224,449,1001,223,1,223,1007,677,226,224,1002,223,2,223,1006,224,464,101,1,223,223,1108,677,677,224,1002,223,2,223,1005,224,479,1001,223,1,223,107,226,226,224,1002,223,2,223,1005,224,494,101,1,223,223,8,226,677,224,102,2,223,223,1006,224,509,101,1,223,223,8,677,677,224,102,2,223,223,1006,224,524,101,1,223,223,1007,226,226,224,1002,223,2,223,1006,224,539,1001,223,1,223,107,677,226,224,102,2,223,223,1006,224,554,101,1,223,223,1107,677,226,224,1002,223,2,223,1006,224,569,1001,223,1,223,1008,226,677,224,102,2,223,223,1006,224,584,1001,223,1,223,1008,226,226,224,1002,223,2,223,1005,224,599,1001,223,1,223,7,677,677,224,1002,223,2,223,1005,224,614,1001,223,1,223,1108,677,226,224,1002,223,2,223,1005,224,629,101,1,223,223,7,226,677,224,1002,223,2,223,1005,224,644,1001,223,1,223,8,677,226,224,102,2,223,223,1005,224,659,101,1,223,223,108,226,226,224,102,2,223,223,1005,224,674,101,1,223,223,4,223,99,226] 5 | icc = IntcodeComputer(instructions) 6 | icc.run(inp=(5,)) 7 | print(icc.out) 8 | -------------------------------------------------------------------------------- /src/day5.py: -------------------------------------------------------------------------------- 1 | from copy import copy 2 | try: 3 | from src.ops5 import * 4 | except: 5 | from ops5 import * 6 | 7 | class IntcodeComputer: 8 | def __init__(self, instructions): 9 | self.memory = copy(instructions) 10 | 11 | def run(self, inp=None): 12 | self.inp = inp 13 | inp_ptr = 0 14 | pc = 0 15 | while pc < len(self.memory): 16 | try: 17 | pc, inp_ptr = self.try_exec(pc, inp_ptr) 18 | except HaltException: 19 | break 20 | return self.memory 21 | 22 | def try_exec(self, pc, inp_ptr): 23 | opcode = self.memory[pc] 24 | ops = OPS_NUM_ARGS.keys() 25 | argmodes, op = opcode // 100, opcode % 100 26 | if op == HALT_CODE: 27 | raise HaltException 28 | elif op in ops: 29 | return self.exec(op, argmodes, pc, inp_ptr) 30 | else: 31 | raise InvalidOpException 32 | 33 | def exec(self, op, argmodes, pc, inp_ptr): 34 | num_args = OPS_NUM_ARGS[op] 35 | args = self.memory[pc+1:pc+1+num_args] 36 | pc += 1 + num_args 37 | if op == 1: 38 | self.two_arg_store(*args, argmodes, add) 39 | elif op == 2: 40 | self.two_arg_store(*args, argmodes, mult) 41 | elif op == 3: 42 | inp = self.inp[inp_ptr] 43 | inp_ptr += 1 44 | self.mem_store(*args, inp) 45 | elif op == 4: 46 | self.out = self.mem_load(*args) 47 | elif op == 5: 48 | pc = self.jump(*args, argmodes, pc, neq_zero) 49 | elif op == 6: 50 | pc = self.jump(*args, argmodes, pc, eq_zero) 51 | elif op == 7: 52 | self.two_arg_store(*args, argmodes, lt) 53 | elif op == 8: 54 | self.two_arg_store(*args, argmodes, eq) 55 | return pc, inp_ptr 56 | 57 | def arg_values(self, argmodes, *args): 58 | decoded_args = [] 59 | for i, arg in enumerate(args): 60 | argmode = argmodes // 10 ** i 61 | if argmode % 10 == 0: 62 | value = self.mem_load(arg) 63 | decoded_args.append(value) 64 | else: 65 | decoded_args.append(arg) 66 | return decoded_args 67 | 68 | def jump(self, a_loc, b_loc, argmodes, pc, jump_to): 69 | a, b = self.arg_values(argmodes, a_loc, b_loc) 70 | return jump_to(a, b, pc) 71 | 72 | def two_arg_store(self, a_loc, b_loc, loc, argmodes, func): 73 | a, b = self.arg_values(argmodes, a_loc, b_loc) 74 | self.mem_store(loc, func(a, b)) 75 | 76 | def mem_load(self, mem_loc): 77 | self.check_mem_inbound(mem_loc) 78 | return self.memory[mem_loc] 79 | 80 | def mem_store(self, mem_loc, value): 81 | self.check_mem_inbound(mem_loc) 82 | self.memory[mem_loc] = value 83 | 84 | def check_mem_inbound(self, mem_loc): 85 | if mem_loc < 0 or mem_loc >= len(self.memory): 86 | print('memory location {mem_loc} is out bounds') 87 | 88 | -------------------------------------------------------------------------------- /tests/test_day5.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from src.day5 import IntcodeComputer, InvalidOpException 3 | 4 | def test_add(): 5 | instructions = [1,4,3,3,99] 6 | expected = [1,4,3,102,99] 7 | actual_eq_expected(instructions, expected) 8 | instructions = [1101,4,3,3,99] 9 | expected = [1101,4,3,7,99] 10 | actual_eq_expected(instructions, expected) 11 | 12 | def test_mult(): 13 | instructions = [2,2,3,3,99] 14 | expected = [2,2,3,9,99] 15 | actual_eq_expected(instructions, expected) 16 | instructions = [1102,2,3,3,99] 17 | expected = [1102,2,3,6,99] 18 | actual_eq_expected(instructions, expected) 19 | 20 | def test_multiple_instructions(): 21 | instructions = [1,9,10,3,2,3,11,0,99,30,40,50] 22 | expected = [3500,9,10,70,2,3,11,0,99,30,40,50] 23 | actual_eq_expected(instructions, expected) 24 | instructions = [1,1,1,4,99,5,6,0,99] 25 | expected = [30,1,1,4,2,5,6,0,99] 26 | actual_eq_expected(instructions, expected) 27 | 28 | def test_immediate_mode(): 29 | instructions = [1002,4,3,4,33] 30 | expected = [1002,4,3,4,3*33] 31 | actual_eq_expected(instructions, expected) 32 | 33 | def test_input_output(): 34 | instructions = [3,0,4,0,99] 35 | inp = (20,) 36 | expected_out = 20 37 | check_output(instructions, inp, expected_out) 38 | 39 | def test_eq_8(): 40 | instructions = [3,9,8,9,10,9,4,9,99,-1,8] 41 | inp = (8,) 42 | expected_out = 1 43 | check_output(instructions, inp, expected_out) 44 | instructions = [3,3,1108,-1,8,3,4,3,99] 45 | check_output(instructions, inp, expected_out) 46 | 47 | def test_neq_8(): 48 | instructions = [3,9,8,9,10,9,4,9,99,-1,8] 49 | not_8 = (7,) 50 | expected_out = 0 51 | check_output(instructions, not_8, expected_out) 52 | instructions = [3,3,1108,-1,8,3,4,3,99] 53 | check_output(instructions, not_8, expected_out) 54 | 55 | def test_lt_8(): 56 | instructions = [3,9,7,9,10,9,4,9,99,-1,8] 57 | lt_8 = (7,) 58 | expected_out = 1 59 | check_output(instructions, lt_8, expected_out) 60 | instructions = [3,3,1107,-1,8,3,4,3,99] 61 | check_output(instructions, lt_8, expected_out) 62 | 63 | def test_jmp_eq0(): 64 | instructions = [1105,1,5,4,1,4,0,99] 65 | expected_out = 1105 66 | check_output(instructions, None, expected_out) 67 | 68 | def test_jmp_neq0(): 69 | instructions = [1106,0,5,4,1,4,0,99] 70 | expected_out = 1106 71 | check_output(instructions, None, expected_out) 72 | 73 | def test_dont_jmp_eq0(): 74 | instructions = [1105,0,6,4,0,99,4,1,99] 75 | expected_out = 1105 76 | check_output(instructions, None, expected_out) 77 | 78 | def test_dont_jmp_neq0(): 79 | instructions = [1106,1,6,4,0,99,4,1,99] 80 | expected_out = 1106 81 | check_output(instructions, None, expected_out) 82 | 83 | @pytest.mark.xfail(raises=InvalidOpException) 84 | def test_fail(): 85 | instructions = [0,0,0,0] 86 | run_instructions(instructions) 87 | 88 | def actual_eq_expected(instructions, expected): 89 | icc = run_instructions(instructions) 90 | actual = icc.memory 91 | assert actual == expected 92 | 93 | def check_output(instructions, inp, expected_out): 94 | icc = run_instructions(instructions, inp=inp) 95 | actual_out = icc.out 96 | assert actual_out == expected_out 97 | 98 | def run_instructions(instructions, inp=None): 99 | icc = IntcodeComputer(instructions) 100 | icc.run(inp=inp) 101 | return icc 102 | 103 | -------------------------------------------------------------------------------- /Pipfile.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "hash": { 4 | "sha256": "828b8ad012f4c8773e6e61e3ac2be0ffcd7540fd7ed175a8355676c8e31c4d3d" 5 | }, 6 | "pipfile-spec": 6, 7 | "requires": { 8 | "python_version": "3.7" 9 | }, 10 | "sources": [ 11 | { 12 | "name": "pypi", 13 | "url": "https://pypi.org/simple", 14 | "verify_ssl": true 15 | } 16 | ] 17 | }, 18 | "default": { 19 | "attrs": { 20 | "hashes": [ 21 | "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c", 22 | "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72" 23 | ], 24 | "version": "==19.3.0" 25 | }, 26 | "importlib-metadata": { 27 | "hashes": [ 28 | "sha256:073a852570f92da5f744a3472af1b61e28e9f78ccf0c9117658dc32b15de7b45", 29 | "sha256:d95141fbfa7ef2ec65cfd945e2af7e5a6ddbd7c8d9a25e66ff3be8e3daf9f60f" 30 | ], 31 | "markers": "python_version < '3.8'", 32 | "version": "==1.3.0" 33 | }, 34 | "more-itertools": { 35 | "hashes": [ 36 | "sha256:b84b238cce0d9adad5ed87e745778d20a3f8487d0f0cb8b8a586816c7496458d", 37 | "sha256:c833ef592a0324bcc6a60e48440da07645063c453880c9477ceb22490aec1564" 38 | ], 39 | "version": "==8.0.2" 40 | }, 41 | "packaging": { 42 | "hashes": [ 43 | "sha256:28b924174df7a2fa32c1953825ff29c61e2f5e082343165438812f00d3a7fc47", 44 | "sha256:d9551545c6d761f3def1677baf08ab2a3ca17c56879e70fecba2fc4dde4ed108" 45 | ], 46 | "version": "==19.2" 47 | }, 48 | "pluggy": { 49 | "hashes": [ 50 | "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0", 51 | "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d" 52 | ], 53 | "version": "==0.13.1" 54 | }, 55 | "py": { 56 | "hashes": [ 57 | "sha256:5e27081401262157467ad6e7f851b7aa402c5852dbcb3dae06768434de5752aa", 58 | "sha256:c20fdd83a5dbc0af9efd622bee9a5564e278f6380fffcacc43ba6f43db2813b0" 59 | ], 60 | "version": "==1.8.1" 61 | }, 62 | "pyparsing": { 63 | "hashes": [ 64 | "sha256:4c830582a84fb022400b85429791bc551f1f4871c33f23e44f353119e92f969f", 65 | "sha256:c342dccb5250c08d45fd6f8b4a559613ca603b57498511740e65cd11a2e7dcec" 66 | ], 67 | "version": "==2.4.6" 68 | }, 69 | "pytest": { 70 | "hashes": [ 71 | "sha256:6b571215b5a790f9b41f19f3531c53a45cf6bb8ef2988bc1ff9afb38270b25fa", 72 | "sha256:e41d489ff43948babd0fad7ad5e49b8735d5d55e26628a58673c39ff61d95de4" 73 | ], 74 | "index": "pypi", 75 | "version": "==5.3.2" 76 | }, 77 | "six": { 78 | "hashes": [ 79 | "sha256:1f1b7d42e254082a9db6279deae68afb421ceba6158efa6131de7b3003ee93fd", 80 | "sha256:30f610279e8b2578cab6db20741130331735c781b56053c59c4076da27f06b66" 81 | ], 82 | "version": "==1.13.0" 83 | }, 84 | "wcwidth": { 85 | "hashes": [ 86 | "sha256:8fd29383f539be45b20bd4df0dc29c20ba48654a41e661925e612311e9f3c603" 87 | ], 88 | "version": "==0.1.8" 89 | }, 90 | "zipp": { 91 | "hashes": [ 92 | "sha256:3718b1cbcd963c7d4c5511a8240812904164b7f381b647143a89d3b98f9bcd8e", 93 | "sha256:f06903e9f1f43b12d371004b4ac7b06ab39a44adc747266928ae6debfa7b3335" 94 | ], 95 | "version": "==0.6.0" 96 | } 97 | }, 98 | "develop": {} 99 | } 100 | -------------------------------------------------------------------------------- /tests/test_day7.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from src.day7 import IntcodeComputer, InvalidOpException, AmplifierCircuit 3 | 4 | def test_add(): 5 | instructions = [1,4,3,3,99] 6 | expected = [1,4,3,102,99] 7 | actual_eq_expected(instructions, expected) 8 | instructions = [1101,4,3,3,99] 9 | expected = [1101,4,3,7,99] 10 | actual_eq_expected(instructions, expected) 11 | 12 | def test_mult(): 13 | instructions = [2,2,3,3,99] 14 | expected = [2,2,3,9,99] 15 | actual_eq_expected(instructions, expected) 16 | instructions = [1102,2,3,3,99] 17 | expected = [1102,2,3,6,99] 18 | actual_eq_expected(instructions, expected) 19 | 20 | def test_multiple_instructions(): 21 | instructions = [1,9,10,3,2,3,11,0,99,30,40,50] 22 | expected = [3500,9,10,70,2,3,11,0,99,30,40,50] 23 | actual_eq_expected(instructions, expected) 24 | instructions = [1,1,1,4,99,5,6,0,99] 25 | expected = [30,1,1,4,2,5,6,0,99] 26 | actual_eq_expected(instructions, expected) 27 | 28 | def test_immediate_mode(): 29 | instructions = [1002,4,3,4,33] 30 | expected = [1002,4,3,4,3*33] 31 | actual_eq_expected(instructions, expected) 32 | 33 | def test_input_output(): 34 | instructions = [3,0,4,0,99] 35 | inp = (20,) 36 | expected_out = 20 37 | check_output(instructions, inp, expected_out) 38 | 39 | def test_eq_8(): 40 | instructions = [3,9,8,9,10,9,4,9,99,-1,8] 41 | inp = (8,) 42 | expected_out = 1 43 | check_output(instructions, inp, expected_out) 44 | instructions = [3,3,1108,-1,8,3,4,3,99] 45 | check_output(instructions, inp, expected_out) 46 | 47 | def test_neq_8(): 48 | instructions = [3,9,8,9,10,9,4,9,99,-1,8] 49 | not_8 = (7,) 50 | expected_out = 0 51 | check_output(instructions, not_8, expected_out) 52 | instructions = [3,3,1108,-1,8,3,4,3,99] 53 | check_output(instructions, not_8, expected_out) 54 | 55 | def test_lt_8(): 56 | instructions = [3,9,7,9,10,9,4,9,99,-1,8] 57 | lt_8 = (7,) 58 | expected_out = 1 59 | check_output(instructions, lt_8, expected_out) 60 | instructions = [3,3,1107,-1,8,3,4,3,99] 61 | check_output(instructions, lt_8, expected_out) 62 | 63 | def test_jmp_eq0(): 64 | instructions = [1105,1,5,4,1,4,0,99] 65 | expected_out = 1105 66 | check_output(instructions, None, expected_out) 67 | 68 | def test_jmp_neq0(): 69 | instructions = [1106,0,5,4,1,4,0,99] 70 | expected_out = 1106 71 | check_output(instructions, None, expected_out) 72 | 73 | def test_dont_jmp_eq0(): 74 | instructions = [1105,0,6,4,0,99,4,1,99] 75 | expected_out = 1105 76 | check_output(instructions, None, expected_out) 77 | 78 | def test_dont_jmp_neq0(): 79 | instructions = [1106,1,6,4,0,99,4,1,99] 80 | expected_out = 1106 81 | check_output(instructions, None, expected_out) 82 | 83 | @pytest.mark.xfail(raises=InvalidOpException) 84 | def test_fail(): 85 | instructions = [0,0,0,0] 86 | run_instructions(instructions) 87 | 88 | def test_thruster(): 89 | instructions = ([3,15,3,16,1002,16,10,16,1,16,15,15,4,15,99,0,0], 90 | [3,23,3,24,1002,24,10,24,1002,23,-1,23, 91 | 101,5,23,23,1,24,23,23,4,23,99,0,0], 92 | [3,31,3,32,1002,32,10,32,1001,31,-2,31,1007,31,0,33, 93 | 1002,33,7,33,1,33,31,31,1,32,31,31,4,31,99,0,0,0]) 94 | max_thrust_setting = ((43210, 43210), 95 | (54321, 1234), 96 | (65210, 10432)) 97 | for instr, ts in zip(instructions, max_thrust_setting): 98 | expected_thrust, expected_setting = ts 99 | ac = AmplifierCircuit(5, instr) 100 | max_thrust, max_setting = ac.get_max_thruster_setting() 101 | assert max_thrust == expected_thrust 102 | assert max_setting == expected_setting 103 | 104 | def actual_eq_expected(instructions, expected): 105 | icc = run_instructions(instructions) 106 | actual = icc.memory 107 | assert actual == expected 108 | 109 | def check_output(instructions, inp, expected_out): 110 | icc = run_instructions(instructions, inp=inp) 111 | actual_out = icc.out[-1] 112 | assert actual_out == expected_out 113 | 114 | def run_instructions(instructions, inp=None): 115 | icc = IntcodeComputer(instructions) 116 | icc.run(inp=inp) 117 | return icc 118 | 119 | -------------------------------------------------------------------------------- /src/day7.py: -------------------------------------------------------------------------------- 1 | from copy import copy 2 | from itertools import permutations 3 | try: 4 | from src.ops7 import * 5 | except: 6 | from ops7 import * 7 | 8 | class IntcodeComputer: 9 | def __init__(self, instructions): 10 | self.memory = copy(instructions) 11 | self.out = [] 12 | 13 | def run(self, inp=None): 14 | self.inp = inp 15 | inp_ptr = 0 16 | pc = 0 17 | while pc < len(self.memory): 18 | try: 19 | pc, inp_ptr = self.try_exec(pc, inp_ptr) 20 | except HaltException: 21 | break 22 | return self.memory 23 | 24 | def try_exec(self, pc, inp_ptr): 25 | opcode = self.memory[pc] 26 | ops = OPS_NUM_ARGS.keys() 27 | argmodes, op = opcode // 100, opcode % 100 28 | if op == HALT_CODE: 29 | raise HaltException 30 | elif op in ops: 31 | return self.exec(op, argmodes, pc, inp_ptr) 32 | else: 33 | raise InvalidOpException 34 | 35 | def exec(self, op, argmodes, pc, inp_ptr): 36 | num_args = OPS_NUM_ARGS[op] 37 | args = self.memory[pc+1:pc+1+num_args] 38 | pc += 1 + num_args 39 | if op == 1: 40 | self.two_arg_store(*args, argmodes, add) 41 | elif op == 2: 42 | self.two_arg_store(*args, argmodes, mult) 43 | elif op == 3: 44 | inp = self.inp[inp_ptr] 45 | inp_ptr += 1 46 | self.mem_store(*args, inp) 47 | elif op == 4: 48 | self.out.append(self.mem_load(*args)) 49 | elif op == 5: 50 | pc = self.jump(*args, argmodes, pc, neq_zero) 51 | elif op == 6: 52 | pc = self.jump(*args, argmodes, pc, eq_zero) 53 | elif op == 7: 54 | self.two_arg_store(*args, argmodes, lt) 55 | elif op == 8: 56 | self.two_arg_store(*args, argmodes, eq) 57 | return pc, inp_ptr 58 | 59 | def arg_values(self, argmodes, *args): 60 | decoded_args = [] 61 | for i, arg in enumerate(args): 62 | argmode = argmodes // 10 ** i 63 | if argmode % 10 == 0: 64 | value = self.mem_load(arg) 65 | decoded_args.append(value) 66 | elif argmode % 10 == 1: 67 | decoded_args.append(arg) 68 | else: 69 | raise InvalidParameterModeException 70 | return decoded_args 71 | 72 | def jump(self, a_loc, b_loc, argmodes, pc, jump_to): 73 | a, b = self.arg_values(argmodes, a_loc, b_loc) 74 | return jump_to(a, b, pc) 75 | 76 | def two_arg_store(self, a_loc, b_loc, loc, argmodes, func): 77 | a, b = self.arg_values(argmodes, a_loc, b_loc) 78 | self.mem_store(loc, func(a, b)) 79 | 80 | def mem_load(self, mem_loc): 81 | self.check_mem_inbound(mem_loc) 82 | return self.memory[mem_loc] 83 | 84 | def mem_store(self, mem_loc, value): 85 | self.check_mem_inbound(mem_loc) 86 | assert type(value) == int, 'value being stored must be an int' 87 | self.memory[mem_loc] = value 88 | 89 | def check_mem_inbound(self, mem_loc): 90 | if mem_loc < 0 or mem_loc >= len(self.memory): 91 | print('memory location {mem_loc} is out bounds') 92 | 93 | class AmplifierCircuit: 94 | def __init__(self, num_thrusters, instructions, start_settings=0): 95 | self.iccs = [IntcodeComputer(instructions) 96 | for _ in range(num_thrusters)] 97 | self.instructions = copy(instructions) 98 | settings = ''.join(str(i) for i in range(start_settings, start_settings + num_thrusters)) 99 | self.possible_settings = permutations(settings) 100 | 101 | def reinit_iccs(self): 102 | self.iccs = [IntcodeComputer(self.instructions) for _ in self.iccs] 103 | 104 | def get_max_thruster_setting(self): 105 | max_thrust = 0 # TODO check if this is really the smallest 106 | for setting in self.possible_settings: 107 | inp = [0] 108 | for i, icc in enumerate(self.iccs): 109 | icc.run(inp=(int(setting[i]), *inp)) 110 | inp = icc.out 111 | 112 | # inp is now output of amp E 113 | amp_out = inp[-1] 114 | if amp_out > max_thrust: 115 | max_thrust = amp_out 116 | max_setting = int(''.join(setting)) 117 | 118 | # Reset memory of all computers 119 | self.reinit_iccs() 120 | return max_thrust, max_setting 121 | 122 | -------------------------------------------------------------------------------- /src/day7_2.py: -------------------------------------------------------------------------------- 1 | from multiprocessing import Queue 2 | from copy import copy 3 | from itertools import permutations 4 | from threading import Thread 5 | try: 6 | from src.ops7 import * 7 | except: 8 | from ops7 import * 9 | 10 | class IntcodeComputer: 11 | def __init__(self, instructions): 12 | self.instructions = copy(instructions) 13 | self.memory = copy(instructions) 14 | self.in_q = Queue() 15 | self.out_q = Queue() 16 | 17 | def reinit(self): 18 | self.memory = copy(self.instructions) 19 | while not self.in_q.empty(): 20 | self.in_q.get_nowait() 21 | while not self.out_q.empty(): 22 | self.out_q.get_nowait() 23 | 24 | def start(self): 25 | self.thread = Thread(target=self.run) 26 | self.thread.start() 27 | 28 | def stop(self): 29 | self.thread.join() 30 | 31 | def send(self, value): 32 | self.in_q.put(value) 33 | 34 | def receive(self): 35 | return self.out_q.get() 36 | 37 | def run(self): 38 | pc = 0 39 | while pc < len(self.memory): 40 | try: 41 | pc = self.try_exec(pc) 42 | except HaltException: 43 | break 44 | 45 | def try_exec(self, pc):#argmodes, pc, inp=None): 46 | opcode = self.memory[pc] 47 | argmodes, op = opcode // 100, opcode % 100 48 | ops = OPS_NUM_ARGS.keys() 49 | if op == HALT_CODE: 50 | raise HaltException 51 | elif op in ops: 52 | return self.exec(op, argmodes, pc) 53 | else: 54 | raise InvalidOpException 55 | 56 | def exec(self, op, argmodes, pc): 57 | num_args = OPS_NUM_ARGS[op] 58 | args = self.memory[pc+1:pc+1+num_args] 59 | pc += 1 + num_args 60 | if op == 1: 61 | self.two_arg_store(*args, argmodes, add) 62 | elif op == 2: 63 | self.two_arg_store(*args, argmodes, mult) 64 | elif op == 3: 65 | try: 66 | inp = self.in_q.get() 67 | except OSError as e: 68 | raise e 69 | self.mem_store(*args, inp) 70 | elif op == 4: 71 | out = self.mem_load(*args) 72 | try: 73 | self.out_q.put(out) 74 | except OSError as e: 75 | raise e 76 | elif op == 5: 77 | pc = self.jump(*args, argmodes, pc, neq_zero) 78 | elif op == 6: 79 | pc = self.jump(*args, argmodes, pc, eq_zero) 80 | elif op == 7: 81 | self.two_arg_store(*args, argmodes, lt) 82 | elif op == 8: 83 | self.two_arg_store(*args, argmodes, eq) 84 | return pc 85 | 86 | def arg_values(self, argmodes, *args): 87 | decoded_args = [] 88 | for i, arg in enumerate(args): 89 | argmode = argmodes // 10 ** i 90 | if argmode % 10 == 0: 91 | value = self.mem_load(arg) 92 | decoded_args.append(value) 93 | elif argmode % 10 == 1: 94 | decoded_args.append(arg) 95 | else: 96 | raise InvalidParameterModeException 97 | return decoded_args 98 | 99 | def jump(self, a_loc, b_loc, argmodes, pc, jump_to): 100 | a, b = self.arg_values(argmodes, a_loc, b_loc) 101 | return jump_to(a, b, pc) 102 | 103 | def two_arg_store(self, a_loc, b_loc, loc, argmodes, func): 104 | a, b = self.arg_values(argmodes, a_loc, b_loc) 105 | self.mem_store(loc, func(a, b)) 106 | 107 | def mem_load(self, mem_loc): 108 | self.check_mem_inbound(mem_loc) 109 | return self.memory[mem_loc] 110 | 111 | def mem_store(self, mem_loc, value): 112 | self.check_mem_inbound(mem_loc) 113 | assert type(value) == int, 'value being stored must be an int' 114 | self.memory[mem_loc] = value 115 | 116 | def check_mem_inbound(self, mem_loc): 117 | if mem_loc < 0 or mem_loc >= len(self.memory): 118 | print('memory location {mem_loc} is out bounds') 119 | 120 | class AmplifierCircuit: 121 | def __init__(self, num_thrusters, instructions, start_settings=0): 122 | self.iccs = [IntcodeComputer(instructions) 123 | for _ in range(num_thrusters)] 124 | settings = ''.join(str(i) for i in range(start_settings, start_settings + num_thrusters)) 125 | self.possible_settings = permutations(settings) 126 | 127 | def reinit_iccs(self): 128 | for icc in self.iccs: 129 | icc.reinit() 130 | 131 | def get_max_thruster_setting(self, run_method): 132 | max_thrust = 0 # TODO check if this is really the smallest 133 | for setting in self.possible_settings: 134 | amp_out = run_method(setting) 135 | if amp_out > max_thrust: 136 | max_thrust = amp_out 137 | max_setting = int(''.join(setting)) 138 | 139 | # Reset memory of all computers 140 | self.reinit_iccs() 141 | return max_thrust, max_setting 142 | 143 | def run_sequentially(self, setting): 144 | inp = 0 145 | for i, icc in enumerate(self.iccs): 146 | icc.start() 147 | icc.send(int(setting[i])) 148 | icc.send(inp) 149 | inp = icc.receive() 150 | icc.stop() 151 | return inp 152 | 153 | def run_loop(self, setting): 154 | for i, icc in enumerate(self.iccs): 155 | icc.in_q = self.iccs[i-1].out_q 156 | for s, icc in zip(setting, self.iccs): 157 | icc.send(int(s)) 158 | self.iccs[0].send(0) 159 | for icc in self.iccs: 160 | icc.start() 161 | for icc in self.iccs: 162 | icc.stop() 163 | while not self.iccs[-1].out_q.empty(): 164 | amp_out = self.iccs[-1].receive() 165 | return amp_out 166 | 167 | --------------------------------------------------------------------------------