11 static int64_t orig
[LIMIT
];
25 static int debug_level
= -1;
27 debug_raw(int level
, const char *fmt
, ...) {
30 debug_level
= atoi(getenv("DEBUG") ?: "0");
31 if (debug_level
>= level
) {
33 vfprintf(stderr
, fmt
, ap
);
37 #define debug(...) debug_raw(1, __VA_ARGS__)
39 static int __attribute__((noreturn
))
40 die(const char *fmt
, ...)
51 dump(struct state
*s
) {
54 debug(" state of id=%d: pc=%d base=%d in=%s%" PRId64
" out=%s%" PRId64
55 " steps=%d\n", s
->id
, s
->pc
, s
->base
,
56 s
->has_in
? "" : "!", s
->in
, s
->has_out
? "" : "!", s
->out
, s
->steps
);
57 for (int i
= 0; i
< len
; i
++)
58 debug_raw(3, "%" PRId64
",", s
->a
[i
]);
62 static void __attribute__((noreturn
))
63 crash(struct state
*s
, const char *msg
) {
64 printf("invalid program id=%d, pc=%d: %s\n", s
->id
, s
->pc
, msg
);
69 get(struct state
*s
, int param
) {
70 int64_t op
= s
->a
[s
->pc
];
75 if (op
> 99999 || op
< 0)
76 crash(s
, "unexpected opcode");
77 if (s
->pc
+ param
> LIMIT
)
78 crash(s
, "memory too short for opcode");
79 value
= s
->a
[s
->pc
+ param
];
82 mode
= (op
/ scale
) % 10;
83 debug_raw(3, "get op=%d mode=%d value=%d\n", op
, mode
, value
);
86 if (value
> LIMIT
|| value
< 0)
87 crash(s
, "in position mode, param beyond memory");
93 if (value
> LIMIT
|| value
< 0)
94 crash(s
, "in relative mode, param beyond memory");
97 crash(s
, "unexpected mode");
102 put(struct state
*s
, int param
, int64_t value
) {
103 int64_t op
= s
->a
[s
->pc
];
108 if (op
> 99999 || op
< 0)
109 crash(s
, "unexpected opcode");
110 if (s
->pc
+ param
> LIMIT
)
111 crash(s
, "memory too short for opcode");
112 offset
= s
->a
[s
->pc
+ param
];
115 mode
= (op
/ scale
) % 10;
116 debug_raw(3, "put op=%d mode=%d value=%d offset=%d\n", op
, mode
, value
, offset
);
119 if (offset
> LIMIT
|| offset
< 0)
120 crash(s
, "in position mode, param beyond memory");
121 s
->a
[offset
] = value
;
125 if (offset
> LIMIT
|| offset
< 0)
126 crash(s
, "in relative mode, param beyond memory");
127 s
->a
[offset
] = value
;
130 crash(s
, "unexpected mode");
135 init(struct state
*s
, int64_t in
) {
136 memset(s
, 0, sizeof *s
);
137 memcpy(s
->a
, orig
, len
* sizeof orig
[0]);
143 /* Returns -1 for stalled on input, 0 for done, 1 for stalled on output */
145 run(struct state
*s
) {
149 debug_raw(2, "executing id=%d step=%d pc=%d base=%" PRId64
" %" PRId64
150 ",%" PRId64
",%" PRId64
",%" PRId64
"\n", s
->id
,
151 s
->steps
++, s
->pc
, s
->base
, s
->a
[s
->pc
], s
->a
[s
->pc
+1],
152 s
->a
[s
->pc
+2], s
->a
[s
->pc
+3]);
153 if (!(s
->steps
% 10000))
154 debug(" steps=%d\n", s
->steps
);
155 if (s
->pc
> LIMIT
|| s
->pc
< 0)
156 crash(s
, "program ran out of bounds");
157 switch (s
->a
[s
->pc
] % 100) {
159 put(s
, 3, get(s
, 1) + get(s
, 2));
163 put(s
, 3, get(s
, 1) * get(s
, 2));
168 debug_raw(2, "id=%d stalling for input\n", s
->id
);
178 debug_raw(2, "id=%d stalling for output\n", s
->id
);
201 put(s
, 3, get(s
, 1) < get(s
, 2));
205 put(s
, 3, get(s
, 1) == get(s
, 2));
209 s
->base
+= get(s
, 1);
210 if (s
->base
< 0 || s
->base
> LIMIT
)
211 crash(s
, "relative base out of bounds");
215 debug_raw(2, "id=%d halting\n", s
->id
);
218 crash(s
, "unexpected opcode");
225 static struct state s
;
228 static int16_t grid
[GRID
][GRID
]; /* -1 unvisited, -2 wall, else distance */
229 static int minx
, maxx
, miny
, maxy
;
230 enum dir
{ N
= 1, S
, W
, E
};
233 display(int x1
, int y1
) {
238 for (y
= miny
; y
<= maxy
; y
++) {
239 for (x
= minx
; x
<= maxx
; x
++) {
240 if (x1
== x
&& y1
== y
) {
244 switch (grid
[y
][x
]) {
245 case -2: debug("#"); break;
246 case -1: debug(" "); break;
247 case 0: debug("_"); break;
248 default: debug("."); break;
253 debug("currently at %d,%d and %d steps away from origin\n",
254 x1
, y1
, grid
[y1
][x1
]);
258 main(int argc
, char **argv
) {
261 int x
, y
, nextx
, nexty
;
263 int part1
= 0, part2
= 0;
267 if (!(stdin
= freopen(argv
[1], "r", stdin
))) {
272 while (scanf("%" SCNd64
"%*[,\n]", &orig
[len
]) == 1)
273 if (len
++ > LIMIT
- 3)
274 die("recompile with larger LIMIT");
275 printf("Read %u slots\n", len
);
279 memset(grid
, -1, sizeof grid
);
280 minx
= maxx
= x
= miny
= maxy
= y
= GRID
/ 2;
286 die("unexpected exit");
292 if (grid
[y
][x
- 1] > -2) { s
.in
= W
; break; }
293 if (grid
[y
- 1][x
] > -2) { s
.in
= N
; break; }
294 if (grid
[y
][x
+ 1] > -2) { s
.in
= E
; break; }
295 if (grid
[y
+ 1][x
] > -2) { s
.in
= S
; break; }
296 die("no path possible from N");
298 if (grid
[y
- 1][x
] > -2) { s
.in
= N
; break; }
299 if (grid
[y
][x
+ 1] > -2) { s
.in
= E
; break; }
300 if (grid
[y
+ 1][x
] > -2) { s
.in
= S
; break; }
301 if (grid
[y
][x
- 1] > -2) { s
.in
= W
; break; }
302 die("no path possible from E");
304 if (grid
[y
][x
+ 1] > -2) { s
.in
= E
; break; }
305 if (grid
[y
+ 1][x
] > -2) { s
.in
= S
; break; }
306 if (grid
[y
][x
- 1] > -2) { s
.in
= W
; break; }
307 if (grid
[y
- 1][x
] > -2) { s
.in
= N
; break; }
308 die("no path possible from S");
310 if (grid
[y
+ 1][x
] > -2) { s
.in
= S
; break; }
311 if (grid
[y
][x
- 1] > -2) { s
.in
= W
; break; }
312 if (grid
[y
- 1][x
] > -2) { s
.in
= N
; break; }
313 if (grid
[y
][x
+ 1] > -2) { s
.in
= E
; break; }
314 die("no path possible from W");
321 case N
: nextx
= x
; nexty
= y
- 1; break;
322 case S
: nextx
= x
; nexty
= y
+ 1; break;
323 case W
: nextx
= x
- 1; nexty
= y
; break;
324 case E
: nextx
= x
+ 1; nexty
= y
; break;
325 default: die("invalid input");
327 debug("tried %c, got %" PRId64
"\n", " NSWE"[s
.in
], s
.out
);
336 if (nextx
< 0 || nextx
>= GRID
|| nexty
< 0 || nexty
>= GRID
)
337 die("recompile with larger GRID");
340 grid
[nexty
][nextx
] = -2;
343 if (grid
[nexty
][nextx
] < 0)
344 grid
[nexty
][nextx
] = grid
[y
][x
] + 1;
345 if (grid
[nexty
][nextx
] > part2
)
346 part2
= grid
[nexty
][nextx
];
352 display(nextx
, nexty
);
354 printf("found it at %d,%d, distance %d\n", nextx
, nexty
,
356 part1
= grid
[y
][x
] + 1;
358 memset(grid
, -1, sizeof grid
);
359 grid
[nexty
][nextx
] = 0;
365 default: die("unexpected output");
369 printf("%d steps to start, %d minutes to fill\n", part1
, part2
);