85 lines
2.5 KiB
Python
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()
|