-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathday25.py
114 lines (101 loc) · 3.47 KB
/
day25.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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
from collections import defaultdict
def read_input() -> list:
instructions = [
instruction.strip().split()
for instruction in open("input/day25.txt").readlines()
]
return instructions
def execute_program(instructions: list, r: dict):
regs = "abcd"
output = []
i = 0
while i < len(instructions) and len(output) < 10:
instr = instructions[i]
op = instr[0]
p1 = instr[1]
p2 = instr[2] if len(instr) > 2 else None
if op == "cpy":
if p2 in regs:
p1 = r[p1] if p1 in regs else int(p1)
r[p2] = p1
i += 1
elif op == "inc":
if p1 in regs:
# peephole optimize inc/dec/jnz loops
"""
cpy a d
cpy 14 c
cpy 182 b
0 >> inc d
dec b
jnz b -2
dec c
jnz c -5
"""
if (
(i + 3) < len(instructions)
and i - 1 >= 0
and instructions[i - 1][0] == "cpy"
and instructions[i + 1][0] == "dec"
and instructions[i + 2][0] == "jnz"
and instructions[i + 3][0] == "dec"
and instructions[i + 4][0] == "jnz"
):
cpysrc, cpydest = instructions[i - 1][1], instructions[i - 1][2]
dec1op = instructions[i + 1][1]
jnz1cond, jnz1off = instructions[i + 2][1], instructions[i + 2][2]
dec2op = instructions[i + 3][1]
jnz2cond, jnz2off = instructions[i + 4][1], instructions[i + 4][2]
if (
cpydest == dec1op
and dec1op == jnz1cond
and dec2op == jnz2cond
and jnz1off == "-2"
and jnz2off == "-5"
):
cpysrc = r[cpysrc] if cpysrc in regs else int(cpysrc)
r[p1] += cpysrc * r[dec2op]
r[dec2op] = 0
r[dec1op] = 0
i += 5
continue
r[p1] += 1
i += 1
elif op == "dec":
if p1 in regs:
r[p1] -= 1
i += 1
elif op == "jnz":
p1 = r[p1] if p1 in regs else int(p1)
p2 = r[p2] if p2 in regs else int(p2)
if p1 != 0:
i += p2
else:
i += 1
elif op == "tgl":
p1 = r[p1] if p1 in regs else int(p1)
target_i = i + p1
if 0 <= target_i < len(instructions):
target = instructions[target_i]
if len(target) == 2:
target[0] = "dec" if target[0] == "inc" else "inc"
else:
target[0] = "cpy" if target[0] == "jnz" else "jnz"
i += 1
elif op == "out":
p1 = r[p1] if p1 in regs else int(p1)
output.append(p1)
i += 1
return output
def puzzles():
instructions = read_input()
output = []
i = 0
while output != [0, 1, 0, 1, 0, 1, 0, 1, 0, 1]:
registers = defaultdict()
registers["a"] = i
output = execute_program(instructions, registers)
i += 1
print("first i:", i - 1)
if __name__ == "__main__":
puzzles()