From 76daaaa199e46fba177a34e93573dafa94873949 Mon Sep 17 00:00:00 2001 From: Lukas Winkler Date: Thu, 5 Dec 2019 20:33:54 +0100 Subject: [PATCH] complete day 5 --- python/5/day5.py | 94 +++++++++++++++++++++++++++++++++++++++++++ python/5/input.txt | 1 + python/5/test_day5.py | 82 ++++++++++++++++++++++++++++++++++++- 3 files changed, 176 insertions(+), 1 deletion(-) create mode 100644 python/5/day5.py create mode 100644 python/5/input.txt diff --git a/python/5/day5.py b/python/5/day5.py new file mode 100644 index 0000000..b4c5b24 --- /dev/null +++ b/python/5/day5.py @@ -0,0 +1,94 @@ +from typing import List, Tuple + +intcode = List[int] +INPUT = 1 + + +def parse_intcode(text: str) -> intcode: + return list(map(int, text.split(","))) + + +def decode_code(code: int): + paramcode, opcode = divmod(code, 100) # splits 12345 into (123,45) + return paramcode, opcode + + +class ParamReader(): + def __init__(self, pointer, cl, paramcode): + self.pointer = pointer + self.cl = cl + self.paramcode = paramcode + + def index(self, id): + return self.cl[self.pointer + id] + + def param(self, id): + param_mode = (self.paramcode // 10 ** (id - 1)) % 10 + if param_mode == 1: + return self.index(id) + elif param_mode == 0: + return self.cl[self.index(id)% len(self.cl)] + else: + raise ValueError(f"invalid parameter code {param_mode} for parameter {id}") + + +def run_intcode(codelist: intcode, input) -> Tuple[intcode, List[int]]: + # codelist.extend([99, 99, 99]) # hack so we don't look over the edge + output = [] + p = 0 # pointer + while True: + paramcode, code = decode_code(codelist[p]) + pr = ParamReader(p, codelist, paramcode) + + if code == 99: + break + if code == 1: + codelist[pr.index(3)] = pr.param(1) + pr.param(2) + elif code == 2: + codelist[pr.index(3)] = pr.param(1) * pr.param(2) + elif code == 3: + codelist[pr.index(1)] = input + elif code == 4: + output.append(pr.param(1)) + elif code == 5: # jump if true + if pr.param(1): + p = pr.param(2) + else: + p += 3 + elif code == 6: # jump if false + if not pr.param(1): + p = pr.param(2) + else: + p += 3 + elif code == 7: # less than + codelist[pr.index(3)] = 1 if (pr.param(1) < pr.param(2)) else 0 + elif code == 8: # equals + codelist[pr.index(3)] = 1 if (pr.param(1) == pr.param(2)) else 0 + else: + raise ValueError(f"invalid intcode: {code}") + if code in [1, 2,7, 8]: + p += 4 + elif code in [3, 4]: + p += 2 + return codelist, output + + +def part1() -> List[int]: + with open("5/input.txt") as f: + cl = parse_intcode(f.read()) + cl, output = run_intcode(cl, input=1) + + return output + + +def part2() -> List[int]: + with open("5/input.txt") as f: + cl = parse_intcode(f.read()) + cl, output = run_intcode(cl, input=5) + + return output + + +if __name__ == '__main__': + # print(part1()) + print(part2()) diff --git a/python/5/input.txt b/python/5/input.txt new file mode 100644 index 0000000..c5c2baa --- /dev/null +++ b/python/5/input.txt @@ -0,0 +1 @@ +3,225,1,225,6,6,1100,1,238,225,104,0,1101,11,91,225,1002,121,77,224,101,-6314,224,224,4,224,1002,223,8,223,1001,224,3,224,1,223,224,223,1102,74,62,225,1102,82,7,224,1001,224,-574,224,4,224,102,8,223,223,1001,224,3,224,1,224,223,223,1101,28,67,225,1102,42,15,225,2,196,96,224,101,-4446,224,224,4,224,102,8,223,223,101,6,224,224,1,223,224,223,1101,86,57,225,1,148,69,224,1001,224,-77,224,4,224,102,8,223,223,1001,224,2,224,1,223,224,223,1101,82,83,225,101,87,14,224,1001,224,-178,224,4,224,1002,223,8,223,101,7,224,224,1,223,224,223,1101,38,35,225,102,31,65,224,1001,224,-868,224,4,224,1002,223,8,223,1001,224,5,224,1,223,224,223,1101,57,27,224,1001,224,-84,224,4,224,102,8,223,223,1001,224,7,224,1,223,224,223,1101,61,78,225,1001,40,27,224,101,-89,224,224,4,224,1002,223,8,223,1001,224,1,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,1008,677,226,224,1002,223,2,223,1006,224,329,101,1,223,223,8,226,677,224,102,2,223,223,1005,224,344,101,1,223,223,1107,226,677,224,102,2,223,223,1006,224,359,101,1,223,223,1007,226,226,224,102,2,223,223,1006,224,374,101,1,223,223,7,677,677,224,102,2,223,223,1005,224,389,1001,223,1,223,108,677,677,224,1002,223,2,223,1005,224,404,101,1,223,223,1008,226,226,224,102,2,223,223,1005,224,419,1001,223,1,223,1107,677,226,224,102,2,223,223,1005,224,434,1001,223,1,223,1108,677,677,224,102,2,223,223,1006,224,449,1001,223,1,223,7,226,677,224,102,2,223,223,1005,224,464,101,1,223,223,1008,677,677,224,102,2,223,223,1005,224,479,101,1,223,223,1007,226,677,224,1002,223,2,223,1006,224,494,101,1,223,223,8,677,226,224,1002,223,2,223,1005,224,509,101,1,223,223,1007,677,677,224,1002,223,2,223,1006,224,524,101,1,223,223,107,226,226,224,102,2,223,223,1006,224,539,101,1,223,223,107,226,677,224,102,2,223,223,1005,224,554,1001,223,1,223,7,677,226,224,102,2,223,223,1006,224,569,1001,223,1,223,107,677,677,224,1002,223,2,223,1005,224,584,101,1,223,223,1107,677,677,224,102,2,223,223,1005,224,599,101,1,223,223,1108,226,677,224,102,2,223,223,1006,224,614,101,1,223,223,8,226,226,224,102,2,223,223,1006,224,629,101,1,223,223,108,226,677,224,102,2,223,223,1005,224,644,1001,223,1,223,108,226,226,224,102,2,223,223,1005,224,659,101,1,223,223,1108,677,226,224,102,2,223,223,1006,224,674,1001,223,1,223,4,223,99,226 diff --git a/python/5/test_day5.py b/python/5/test_day5.py index ec1ef59..c1463bf 100644 --- a/python/5/test_day5.py +++ b/python/5/test_day5.py @@ -1,4 +1,8 @@ -from day5 import run_intcode, decode_code, part1 +from day5 import run_intcode, decode_code, part1, part2 + +complex = [3, 21, 1008, 21, 8, 20, 1005, 20, 22, 107, 8, 21, 20, 1006, 20, 31, + 1106, 0, 36, 98, 0, 0, 1002, 21, 125, 20, 4, 20, 1105, 1, 46, 104, + 999, 1105, 1, 46, 1101, 1000, 1, 20, 4, 20, 1105, 1, 46, 98, 99] def test_new_opcodes(): @@ -19,3 +23,79 @@ def test_decode_code(): def test_part1(): assert part1() == [0, 0, 0, 0, 0, 0, 0, 0, 0, 7286649] + + +def test_advanced1_false(): + assert run_intcode( + [3, 9, 8, 9, 10, 9, 4, 9, 99, -1, 8], input=42) == ([3, 9, 8, 9, 10, 9, 4, 9, 99, 0, 8], [0]) + + +def test_advanced1_true(): + assert run_intcode( + [3, 9, 8, 9, 10, 9, 4, 9, 99, -1, 8], input=8) == ([3, 9, 8, 9, 10, 9, 4, 9, 99, 1, 8], [1]) + + +def test_advanced2_false(): + assert run_intcode( + [3, 9, 7, 9, 10, 9, 4, 9, 99, -1, 8], input=10) == ([3, 9, 7, 9, 10, 9, 4, 9, 99, 0, 8], [0]) + + +def test_advanced2_true(): + assert run_intcode( + [3, 9, 7, 9, 10, 9, 4, 9, 99, -1, 8], input=5) == ([3, 9, 7, 9, 10, 9, 4, 9, 99, 1, 8], [1]) + + +def test_advanced3_false(): + assert run_intcode( + [3, 3, 1108, -1, 8, 3, 4, 3, 99], input=10) == ([3, 3, 1108, 0, 8, 3, 4, 3, 99], [0]) + + +def test_advanced3_true(): + assert run_intcode( + [3, 3, 1108, -1, 8, 3, 4, 3, 99], input=8) == ([3, 3, 1108, 1, 8, 3, 4, 3, 99], [1]) + + +def test_advanced4_false(): + assert run_intcode( + [3, 3, 1107, -1, 8, 3, 4, 3, 99], input=10) == ([3, 3, 1107, 0, 8, 3, 4, 3, 99], [0]) + + +def test_advanced4_true(): + assert run_intcode( + [3, 3, 1107, -1, 8, 3, 4, 3, 99], input=5) == ([3, 3, 1107, 1, 8, 3, 4, 3, 99], [1]) + + +def test_jump1_nonzero(): + assert run_intcode( + [3, 12, 6, 12, 15, 1, 13, 14, 13, 4, 13, 99, -1, 0, 1, 9], input=5)[1][0] == 1 + + +def test_jump1_zero(): + assert run_intcode( + [3, 12, 6, 12, 15, 1, 13, 14, 13, 4, 13, 99, -1, 0, 1, 9], input=0)[1][0] == 0 + + +def test_jump2_nonzero(): + assert run_intcode( + [3, 3, 1105, -1, 9, 1101, 0, 0, 12, 4, 12, 99, 1], input=5)[1][0] == 1 + + +def test_jump2_zero(): + assert run_intcode( + [3, 3, 1105, -1, 9, 1101, 0, 0, 12, 4, 12, 99, 1], input=0)[1][0] == 0 + + +def test_complex_below_8(): + assert run_intcode(complex, input=5)[1][0] == 999 + + +def test_complex_8(): + assert run_intcode(complex, input=8)[1][0] == 1000 + + +def test_complex_above_8(): + assert run_intcode(complex, input=15)[1][0] == 1001 + + +def test_part2(): + assert part2() == [15724522]