advent-of-code/2020-python/solutions/day_08.py
2021-11-01 16:45:03 +01:00

85 lines
2.5 KiB
Python

from solutions import BaseSolution
class Solution(BaseSolution):
input_file = "08.txt"
def __str__(self):
return "Day 8: Handheld Halting"
def parse_input(self, data):
def parse(l):
op, change = l.split()
return (op, int(change))
return [parse(line) for line in data.splitlines()]
def solve(self, puzzle_input):
_, acc = self.run(puzzle_input)
return acc
def solve_again(self, puzzle_input):
stop_at = len(puzzle_input)
tried = 0
i = 0
offset = 0
while tried <= stop_at and i < stop_at:
instructions, offset = self.alter(puzzle_input, offset)
exit_code, acc = self.run(instructions)
if exit_code == "ok":
return acc
i += 1
def run(self, instructions):
seen = set()
caretpos = 0
acc = 0
stop_at = len(instructions)
while len(seen) < stop_at:
if caretpos == stop_at:
return "ok", acc
if caretpos % stop_at in seen:
return "exit", acc
seen.add(caretpos)
acc, caretpos = self.execute(instructions, caretpos % stop_at, acc)
def execute(self, instructions, caretpos, acc):
op, change = instructions[caretpos]
if op == "nop":
return acc, caretpos + 1
if op == "jmp":
return acc, caretpos + change
if op == "acc":
return acc + change, caretpos + 1
def alter(self, instructions, offset):
il = len(instructions)
invalid_changes = [0, il, -il]
dont = "DO_NOT_ALTER"
def sanitize(instruction):
op, change = instruction
if op == "nop" and change in invalid_changes:
return (dont, change)
return (op, change)
change_range = [op for op, _change in map(sanitize, instructions[offset:])]
try:
first_jmp = change_range.index("jmp")
except ValueError:
first_jmp = il - offset - 1
try:
first_nop = change_range.index("nop")
except ValueError:
first_nop = il - offset - 1
change_at = offset + min(first_nop, first_jmp)
altered = [*instructions]
old_op, change = altered[change_at]
new_op = "jmp" if old_op == "nop" else "nop"
altered[change_at] = (new_op, change)
return altered, change_at + 1
if __name__ == "__main__":
solution = Solution()
solution.show_results()