-
Notifications
You must be signed in to change notification settings - Fork 16
/
Copy pathday17.py
executable file
·141 lines (109 loc) · 2.83 KB
/
day17.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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#!/usr/bin/env python3
import sys
from lib.intcode import IntcodeVM
EMPTY, SCAFFOLD = '.#'
NORTH, SOUTH, WEST, EAST = range(4)
LEFT = (WEST, EAST, SOUTH, NORTH)
RIGHT = (EAST, WEST, NORTH, SOUTH)
MOVE_DELTA = ((-1, 0), (+1, 0), (0, -1), (0, +1))
def get_moves(grid, startpos, startdir):
columns = len(grid[0])
grid = [EMPTY * columns] + grid + [EMPTY * columns]
for i in range(len(grid)):
grid[i] = EMPTY + grid[i] + EMPTY
r, c = startpos
curdir = startdir
moves = []
steps = 0
r += 1
c += 1
while 1:
dr, dc = MOVE_DELTA[curdir]
newr, newc = r + dr, c + dc
if grid[newr][newc] == SCAFFOLD:
steps += 1
r, c = newr, newc
continue
newdir = LEFT[curdir]
dr, dc = MOVE_DELTA[newdir]
newr, newc = r + dr, c + dc
if grid[newr][newc] == SCAFFOLD:
turn = 'L'
else:
newdir = RIGHT[curdir]
dr, dc = MOVE_DELTA[newdir]
newr, newc = r + dr, c + dc
if grid[newr][newc] == SCAFFOLD:
turn = 'R'
else:
moves.append(str(steps))
break
if steps > 0:
moves.append(str(steps))
moves.append(turn)
r, c = newr, newc
curdir = newdir
steps = 1
return moves
def find_functions(moves):
for la in range(2, 11):
func_a = moves[:la]
sb = la
while moves[sb:][:la] == func_a:
sb += la
for lb in range(2, 11):
func_b = moves[sb:sb + lb]
sc = sb + lb
while 1:
if moves[sc:][:la] == func_a:
sc += la
elif moves[sc:][:lb] == func_b:
sc += lb
else:
break
for lc in range(2, 11):
func_c = moves[sc:sc + lc]
ok = True
i = sc
while i < len(moves):
if moves[i:][:la] == func_a:
i += la
elif moves[i:][:lb] == func_b:
i += lb
elif moves[i:][:lc] == func_c:
i += lc
else:
ok = False
break
if ok:
A = ','.join(func_a)
B = ','.join(func_b)
C = ','.join(func_c)
if len(A) <= 20 and len(B) <= 20 and len(C) <= 20:
return A, B, C
# Open the first argument as input or use stdin if no arguments were given
fin = open(sys.argv[1]) if len(sys.argv) > 1 else sys.stdin
program = list(map(int, fin.read().split(',')))
vm = IntcodeVM(program)
out = vm.run()
grid = ''.join(map(chr, out)).strip().splitlines()
rows, columns = len(grid), len(grid[0])
answer = 0
for r in range(1, rows - 1):
for c in range(1, columns - 1):
if grid[r][c] == SCAFFOLD:
n = sum((grid[rr][cc] == SCAFFOLD for rr, cc in ((r+1, c), (r-1, c), (r, c+1), (r, c-1))))
if n == 4:
answer += r * c
elif grid[r][c] in '^v<>':
startpos = (r, c)
startdir = '^v<>'.index(grid[r][c])
print('Part 1:', answer)
moves = get_moves(grid, startpos, startdir)
A, B, C = find_functions(moves)
main = ','.join(moves).replace(A, 'A').replace(B, 'B').replace(C, 'C')
robot_prog = list(map(ord, '{}\n{}\n{}\n{}\nn\n'.format(main, A, B, C)))
vm.reset()
vm.code[0] = 2
answer = vm.run(robot_prog)[-1]
print('Part 2:', answer)