13 static int64_t orig
[LIMIT
];
27 static int debug_level
= -1;
31 debug_level
= atoi(getenv("DEBUG") ?: "0");
34 static void __attribute__((format(printf
, 2, 3)))
35 debug_raw(int level
, const char *fmt
, ...) {
37 if (debug_level
>= level
) {
39 vfprintf(stderr
, fmt
, ap
);
43 #define debug(...) debug_raw(1, __VA_ARGS__)
45 static int __attribute__((noreturn
)) __attribute__((format(printf
, 1, 2)))
46 die(const char *fmt
, ...)
57 dump(struct state
*s
) {
60 debug(" state of id=%d: pc=%d base=%d in=%s%" PRId64
" out=%s%" PRId64
61 " steps=%d\n", s
->id
, s
->pc
, s
->base
,
62 s
->has_in
? "" : "!", s
->in
, s
->has_out
? "" : "!", s
->out
, s
->steps
);
63 for (int i
= 0; i
< len
; i
++)
64 debug_raw(3, "%" PRId64
",", s
->a
[i
]);
68 static void __attribute__((noreturn
))
69 crash(struct state
*s
, const char *msg
) {
70 printf("invalid program id=%d, pc=%d: %s\n", s
->id
, s
->pc
, msg
);
75 get(struct state
*s
, int param
) {
76 int64_t op
= s
->a
[s
->pc
];
81 if (op
> 99999 || op
< 0)
82 crash(s
, "unexpected opcode");
83 if (s
->pc
+ param
> LIMIT
)
84 crash(s
, "memory too short for opcode");
85 value
= s
->a
[s
->pc
+ param
];
88 mode
= (op
/ scale
) % 10;
89 debug_raw(3, "get op=%" PRId64
" mode=%d value=%" PRId64
"\n",
93 if (value
> LIMIT
|| value
< 0)
94 crash(s
, "in position mode, param beyond memory");
100 if (value
> LIMIT
|| value
< 0)
101 crash(s
, "in relative mode, param beyond memory");
104 crash(s
, "unexpected mode");
109 put(struct state
*s
, int param
, int64_t value
) {
110 int64_t op
= s
->a
[s
->pc
];
115 if (op
> 99999 || op
< 0)
116 crash(s
, "unexpected opcode");
117 if (s
->pc
+ param
> LIMIT
)
118 crash(s
, "memory too short for opcode");
119 offset
= s
->a
[s
->pc
+ param
];
122 mode
= (op
/ scale
) % 10;
123 debug_raw(3, "put op=%" PRId64
" mode=%d value=%" PRId64
" offset=%" PRId64
124 "\n", op
, mode
, value
, offset
);
127 if (offset
> LIMIT
|| offset
< 0)
128 crash(s
, "in position mode, param beyond memory");
129 s
->a
[offset
] = value
;
133 if (offset
> LIMIT
|| offset
< 0)
134 crash(s
, "in relative mode, param beyond memory");
135 s
->a
[offset
] = value
;
138 crash(s
, "unexpected mode");
143 init(struct state
*s
, int64_t in
) {
144 memset(s
, 0, sizeof *s
);
145 memcpy(s
->a
, orig
, len
* sizeof orig
[0]);
151 /* Returns -1 for stalled on input, 0 for done, 1 for stalled on output */
153 run(struct state
*s
) {
157 debug_raw(2, "executing id=%d step=%d pc=%d base=%d %" PRId64
158 ",%" PRId64
",%" PRId64
",%" PRId64
"\n", s
->id
,
159 s
->steps
++, s
->pc
, s
->base
, s
->a
[s
->pc
], s
->a
[s
->pc
+1],
160 s
->a
[s
->pc
+2], s
->a
[s
->pc
+3]);
161 if (!(s
->steps
% 10000))
162 debug(" steps=%d\n", s
->steps
);
163 if (s
->pc
> LIMIT
|| s
->pc
< 0)
164 crash(s
, "program ran out of bounds");
165 switch (s
->a
[s
->pc
] % 100) {
167 put(s
, 3, get(s
, 1) + get(s
, 2));
171 put(s
, 3, get(s
, 1) * get(s
, 2));
176 debug_raw(2, "id=%d stalling for input\n", s
->id
);
186 debug_raw(2, "id=%d stalling for output\n", s
->id
);
209 put(s
, 3, get(s
, 1) < get(s
, 2));
213 put(s
, 3, get(s
, 1) == get(s
, 2));
217 s
->base
+= get(s
, 1);
218 if (s
->base
< 0 || s
->base
> LIMIT
)
219 crash(s
, "relative base out of bounds");
223 debug_raw(2, "id=%d halting\n", s
->id
);
226 crash(s
, "unexpected opcode");
233 static struct state s
;
236 static char grid
[GRID
][GRID
];
237 static int maxx
, maxy
;
245 for (y
= 0; y
<= maxy
; y
++)
246 for (x
= 0; x
<= maxx
; x
++)
247 debug("%c", grid
[y
][x
]);
250 enum dir
{ U
= '^', R
= '>', D
= 'v', L
= '<', NONE
= 0 };
253 next(int x
, int y
, enum dir d
) {
256 if (x
&& grid
[y
][x
- 1] == '#')
258 if (x
< maxx
&& grid
[y
][x
+ 1] == '#')
261 if (y
&& grid
[y
- 1][x
] == '#')
263 if (y
< maxy
&& grid
[y
+ 1][x
] == '#')
267 if (x
&& grid
[y
][x
- 1] == '#')
269 if (x
< maxx
&& grid
[y
][x
+ 1] == '#')
273 if (y
&& grid
[y
- 1][x
] == '#')
275 if (y
< maxy
&& grid
[y
+ 1][x
] == '#')
279 die("unexpected case");
285 walk(int *x
, int *y
, enum dir d
) {
289 while (*y
&& grid
[*y
- 1][*x
] == '#') {
295 while (*x
< maxx
&& grid
[*y
][*x
+ 1] == '#') {
301 while (*y
< maxy
&& grid
[*y
+ 1][*x
] == '#') {
307 while (*x
&& grid
[*y
][*x
- 1] == '#') {
313 die("unexpected case");
319 main(int argc
, char **argv
) {
321 int x
= 0, y
= 0, i
, j
, dir
= NONE
;
326 if (argc
> 1 && strcmp("-", argv
[1]))
327 if (!(stdin
= freopen(argv
[1], "r", stdin
))) {
332 while (scanf("%" SCNd64
"%*[,\n]", &orig
[len
]) == 1)
333 if (len
++ > LIMIT
- 3)
334 die("recompile with larger LIMIT");
335 printf("Read %u slots\n", len
);
342 die("expecting output");
348 if (s
.out
!= '.' && s
.out
!= '#') {
353 if (x
> 1 && y
> 0 && s
.out
== '#' && grid
[y
][x
- 1] == '#' &&
354 grid
[y
][x
- 2] == '#' && grid
[y
- 1][x
- 1] == '#')
355 part1
+= (x
- 1) * y
;
359 if (x
>= GRID
|| y
>= GRID
)
360 die("recompile with larger GRID");
364 printf("%d outputs, start at %d,%d, checksum %d\n", count
, i
, j
, part1
);
366 die("could not find start location");
368 /* Compute the path */
370 char scratch
[MAXFN
* MAXFN
] = "";
371 char a
[MAXFN
], b
[MAXFN
], c
[MAXFN
], m
[MAXFN
];
372 char *pa
, *pb
, *pc
, *pm
;
373 int nextdir
= next(i
, j
, dir
);
375 int paira
, pairb
, pairc
;
378 while (nextdir
!= NONE
) {
380 if ((dir
== U
&& nextdir
== R
) || (dir
== R
&& nextdir
== D
) ||
381 (dir
== D
&& nextdir
== L
) || (dir
== L
&& nextdir
== U
))
382 p
+= sprintf(p
, "R,");
384 p
+= sprintf(p
, "L,");
386 p
+= sprintf(p
, "%d,", walk(&i
, &j
, dir
));
387 nextdir
= next(i
, j
, dir
);
389 printf("computed %s\n", scratch
);
390 /* Brute force compression: assumes that each function contains 1-5 pairs */
391 for (paira
= 1; !done
&& paira
<= 5; paira
++) {
393 memset(m
, 0, sizeof m
);
398 if ((*pa
++ = *p
++) == ',')
400 } while (i
< paira
* 2);
406 for (pairb
= 1; !done
&& pairb
<= 5; pairb
++) {
409 while (!strncmp(p
, a
, pa
- a
)) {
417 if ((*pb
++ = *p
++) == ',')
419 } while (i
< pairb
* 2);
425 for (pairc
= 1; !done
&& pairc
<= 5; pairc
++) {
428 while (!strncmp(p
, a
, pa
- a
) ||
429 !strncmp(p
, b
, pb
- b
)) {
430 if (!strncmp(p
, a
, pa
- a
)) {
442 if ((*pc
++ = *p
++) == ',')
444 } while (i
< pairc
* 2);
450 debug("trying A=%s B=%s C=%s ...", a
, b
, c
);
452 if (!strncmp(p
, a
, pa
- a
)) {
456 } else if (!strncmp(p
, b
, pb
- b
)) {
460 } else if (!strncmp(p
, c
, pc
- c
)) {
478 die("unable to compress");
479 debug("compressed: %s\n", m
);
480 p
= stpcpy(scratch
, m
);
488 *p
++ = argc
> 2 ? argv
[2][0] : 'n';
491 printf("input will be:\n%s", scratch
);
493 /* And finally use the input */
498 while (run(&s
) && *p
) {
501 debug("read '%c'\n", (char)s
.out
);
503 die("unexpected output %" PRId64
, s
.out
);
508 die("expecting input to be consumed");
513 die("unconsumed input: %s", p
);
514 printf("begin output stream\n");
515 while (s
.has_out
&& isascii(s
.out
)) {
519 die("no input to provide");
522 die("expecting output");
523 printf("collected %" PRId64
" dust\n", s
.out
);