| 
 | 1 | +from assertions import assert_equals  | 
 | 2 | +from input_reader import read_lines  | 
 | 3 | +from printer import aoc_print  | 
 | 4 | + | 
 | 5 | + | 
 | 6 | +class Program():  | 
 | 7 | + def __init__(self, instructions: [str]):  | 
 | 8 | + self.accumulator = 0  | 
 | 9 | + self.instruction_pointer = 0  | 
 | 10 | + self.instructions = list(instructions)  | 
 | 11 | + | 
 | 12 | + def run(self):  | 
 | 13 | + instruction = instructions[self.instruction_pointer]  | 
 | 14 | + op_code = instruction.split(" ")[0]  | 
 | 15 | + | 
 | 16 | + self.instruction_pointer += 1  | 
 | 17 | + | 
 | 18 | + if op_code == "nop":  | 
 | 19 | + pass  | 
 | 20 | + elif op_code == "jmp":  | 
 | 21 | + self.instruction_pointer += int(instruction.split(" ")[1]) - 1  | 
 | 22 | + elif op_code == "acc":  | 
 | 23 | + self.accumulator += int(instruction.split(" ")[1])  | 
 | 24 | + else:  | 
 | 25 | + print("invalid instruction")  | 
 | 26 | + | 
 | 27 | + def run_all(self):  | 
 | 28 | + while self.instruction_pointer < len(instructions):  | 
 | 29 | + self.run()  | 
 | 30 | + | 
 | 31 | + def terminates(self) -> bool:  | 
 | 32 | + executed_lines = set()  | 
 | 33 | + | 
 | 34 | + while self.instruction_pointer not in executed_lines:  | 
 | 35 | + executed_lines.add(program.instruction_pointer)  | 
 | 36 | + | 
 | 37 | + if self.instruction_pointer >= len(self.instructions):  | 
 | 38 | + return True  | 
 | 39 | + | 
 | 40 | + self.run()  | 
 | 41 | + | 
 | 42 | + return False  | 
 | 43 | + | 
 | 44 | + | 
 | 45 | +instructions = read_lines("day08")  | 
 | 46 | +program = Program(instructions)  | 
 | 47 | + | 
 | 48 | +# Part one  | 
 | 49 | +program.terminates()  | 
 | 50 | + | 
 | 51 | +aoc_print(f"The program gets interrupted with an accumulator of {program.accumulator}.")  | 
 | 52 | +assert_equals(1801, program.accumulator)  | 
 | 53 | + | 
 | 54 | + | 
 | 55 | +# Part two  | 
 | 56 | +def replace_all(base_list: [str], old: str, new: str) -> [[str]]:  | 
 | 57 | + total = list()  | 
 | 58 | + index = 0  | 
 | 59 | + | 
 | 60 | + while True:  | 
 | 61 | + tup = replace(list(base_list), old, new, index)  | 
 | 62 | + if tup[1] == -1:  | 
 | 63 | + break  | 
 | 64 | + | 
 | 65 | + total.append(tup[0])  | 
 | 66 | + index = tup[1]  | 
 | 67 | + | 
 | 68 | + return total  | 
 | 69 | + | 
 | 70 | + | 
 | 71 | +def replace(replacement_list: [str], old: str, new: str, start: int) -> ([str], int):  | 
 | 72 | + for i in range(start, len(replacement_list)):  | 
 | 73 | + if old in replacement_list[i]:  | 
 | 74 | + replacement_list[i] = replacement_list[i].replace(old, new)  | 
 | 75 | + return replacement_list, i + 1  | 
 | 76 | + | 
 | 77 | + return [], -1  | 
 | 78 | + | 
 | 79 | + | 
 | 80 | +replaced_instructions_list = replace_all(instructions, "jmp", "nop") \  | 
 | 81 | + + replace_all(instructions, "nop", "jmp")  | 
 | 82 | + | 
 | 83 | +for instructions in replaced_instructions_list:  | 
 | 84 | + program = Program(instructions)  | 
 | 85 | + if program.terminates():  | 
 | 86 | + program = Program(instructions)  | 
 | 87 | + program.run_all()  | 
 | 88 | + | 
 | 89 | + aoc_print(f"The program terminates with an accumulator of {program.accumulator}.")  | 
 | 90 | + assert_equals(2060, program.accumulator)  | 
0 commit comments