-
Notifications
You must be signed in to change notification settings - Fork 0
/
day8.py
92 lines (81 loc) · 2.97 KB
/
day8.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
from collections import defaultdict
from util import read_lines_as_list
class Instruction(object):
def __init__(self, line):
self.line = line
def execute(self, acc, ptr):
acc_change = 0
ptr_change = 0
if self.instruction_type == 'nop':
ptr_change = 1
elif self.instruction_type == 'jmp':
ptr_change = int(self.line.lstrip('jmp '))
elif self.instruction_type == 'acc':
acc_change = int(self.line.lstrip('acc '))
ptr_change = 1
else:
raise Exception("Naughty list!!!")
return acc + acc_change, ptr + ptr_change
def change_and_execute(self, acc, ptr):
old_line = str(self.line)
if self.instruction_type == 'jmp':
self.line = self.line.replace('jmp', 'nop')
elif self.instruction_type == 'nop':
self.line = self.line.replace('nop', 'jmp')
else:
raise Exception("YOU ARE NAUGHTY!")
new_acc, new_ptr = self.execute(acc, ptr)
self.line = old_line
return new_acc, new_ptr
@property
def instruction_type(self):
if self.line.startswith('nop'):
return 'nop'
elif self.line.startswith('jmp'):
return 'jmp'
elif self.line.startswith('acc'):
return 'acc'
else:
raise Exception("WTF IS THIS?")
def part1():
input_data = read_lines_as_list('data/day8.txt')
instructions = [Instruction(data) for data in input_data]
lines_executed = set()
acc = 0
ptr = 0
while ptr not in lines_executed:
lines_executed.add(ptr)
acc, ptr = instructions[ptr].execute(acc, ptr)
return acc
def find_broken_lines(instructions):
lines_executed = defaultdict(int)
acc = 0
ptr = 0
while lines_executed[ptr] < 3:
lines_executed[ptr] += 1
acc, ptr = instructions[ptr].execute(acc, ptr)
# only allowed to switch from jump -> acc or acc -> jump
return [idx for idx in list(lines_executed.keys()) if instructions[idx].instruction_type != 'acc']
def fix_program_and_get_acc(instructions, fix_line):
lines_executed = set()
acc = 0
ptr = 0
while ptr not in lines_executed and ptr < len(instructions):
lines_executed.add(ptr)
instruction = instructions[ptr]
if ptr == fix_line:
acc, ptr = instruction.change_and_execute(acc, ptr)
else:
acc, ptr = instruction.execute(acc, ptr)
return acc if ptr == len(instructions) else None
def part2():
input_data = read_lines_as_list('data/day8.txt')
instructions = [Instruction(data) for data in input_data]
broken_lines = find_broken_lines(instructions)
fix_attempts = [fix_program_and_get_acc(instructions, bl) for bl in broken_lines]
answer = [fa for fa in fix_attempts if fa is not None]
assert len(answer) == 1, "you did this problem wrong dude"
return answer[0]
if __name__ == '__main__':
print(part1())
print(part2())