main.c (11146B)
1#include "allocator.h" 2#include "aoc.h" 3#include "iccmp.h" 4#include "dvec_s.h" 5#include "vec_s.h" 6#include "hmap_s.h" 7#include "util.h" 8 9#include <assert.h> 10#include <stdbool.h> 11#include <stdint.h> 12#include <stdio.h> 13#include <stdlib.h> 14 15#define DIR_COUNT 15 16 17struct path { 18 uint8_t dir[DIR_COUNT]; 19 uint8_t dircnt; 20}; 21 22struct room { 23 char *name; 24 struct path path; 25 uint8_t doors; 26 struct dvec items; 27}; 28 29struct state { 30 uint8_t next; 31 uint8_t back; 32}; 33 34bool 35path_hmap_keycmp(struct hmap_key k1, struct hmap_key k2) 36{ 37 const struct path *p1 = k1.p, *p2 = k2.p; 38 39 return p1->dircnt == p2->dircnt 40 && !memcmp(p1->dir, p2->dir, p1->dircnt); 41} 42 43uint32_t 44path_hmap_hash(struct hmap_key k) 45{ 46 const struct path *s = k.p; 47 uint32_t hash; 48 uint8_t i; 49 50 hash = 0; 51 for (i = 0; i < MIN(8, s->dircnt); i++) 52 hash = (hash << 2) | s->dir[i]; 53 54 return hash; 55} 56 57const char * 58path_str(struct path *path) 59{ 60 static char buf[256]; 61 size_t i, len; 62 ssize_t n; 63 64 len = 0; 65 for (i = 0; i < path->dircnt && len < sizeof(buf); i++) { 66 if (len) { 67 n = snprintf(buf + len, sizeof(buf) - len, 68 " -> %c", adj_c[path->dir[i]]); 69 } else { 70 n = snprintf(buf + len, sizeof(buf) - len, 71 "%c", adj_c[path->dir[i]]); 72 } 73 if (n <= 0) break; 74 len += (size_t) n; 75 } 76 77 buf[len] = '\0'; 78 79 return buf; 80} 81 82void 83read_output(struct icc *icc, struct dvec *out) 84{ 85 const char *lpos, *lend; 86 char line[256]; 87 char *c; 88 89 dvec_clear(out); 90 while (1) { 91 switch (icc->state) { 92 case ICC_OUTPUT: 93 c = dvec_add_slot(out); 94 *c = (char) mi_cast_uls(&icc->out); 95 break; 96 case ICC_RUN: 97 break; 98 default: 99 goto exit; 100 } 101 icc_step_inst(icc); 102 } 103 104exit: 105 c = dvec_add_slot(out); 106 *c = '\0'; 107 108 if (aoc.debug == 2) { 109 lpos = out->data; 110 lend = out->data + out->len; 111 while (readtok(line, sizeof(line), '\n', &lpos, lend)) 112 aoc_debug("OUT > %s\n", line); 113 aoc_debug("\n"); 114 } 115} 116 117void 118feed_input(struct icc *icc, struct dvec *input) 119{ 120 size_t i; 121 char *c; 122 123 if (aoc.debug == 2) 124 aoc_debug("\nIN < %.*s", input->len, input->data); 125 126 i = 0; 127 while (i < input->len) { 128 switch (icc->state) { 129 case ICC_INPUT: 130 c = dvec_at(input, i); 131 mi_setv(&icc->in, (mi_ul) *c, MI_POS); 132 i += 1; 133 break; 134 case ICC_RUN: 135 break; 136 default: 137 return; 138 } 139 icc_step_inst(icc); 140 } 141} 142 143void 144parse_output(struct dvec *out, char **title, uint8_t *dirs, struct dvec *items) 145{ 146 const char *lpos, *lend; 147 char line[256]; 148 int state; 149 char *c, *item; 150 151 state = 0; 152 *dirs = 0; 153 *title = NULL; 154 lpos = out->data; 155 lend = lpos + out->len; 156 while (readtok(line, sizeof(line), '\n', &lpos, lend)) { 157 if (!strcmp(line, "Doors here lead:")) { 158 state = 1; 159 } else if (!strcmp(line, "Items here:")) { 160 state = 2; 161 } else if (state == 0 && !strncmp(line, "== ", 3)) { 162 c = strrchr(line, ' '); 163 *c = '\0'; 164 *title = strdup(line + 3); 165 } else if (state == 1 && !strncmp(line, "- ", 2)) { 166 if (!strcmp(line + 2, "north")) { 167 *dirs |= (1 << ADJ_NORTH); 168 } else if (!strcmp(line + 2, "east")) { 169 *dirs |= (1 << ADJ_EAST); 170 } else if (!strcmp(line + 2, "south")) { 171 *dirs |= (1 << ADJ_SOUTH); 172 } else if (!strcmp(line + 2, "west")) { 173 *dirs |= (1 << ADJ_WEST); 174 } else { 175 assert(0); 176 } 177 } else if (state == 2 && !strncmp(line, "- ", 2)) { 178 item = strdup(line + 2); 179 *(char **)dvec_add_slot(items) = item; 180 } 181 } 182} 183 184int 185explore(struct icc *icc, struct dvec *in, struct dvec *out, struct hmap *states, 186 struct hmap *map, struct path *path, struct dvec *items) 187{ 188 struct hmap_link *link, **linkp; 189 struct path *key; 190 struct state *state; 191 struct room *room; 192 char **name; 193 size_t dir; 194 195 read_output(icc, out); 196 197 link = hmap_get(states, (struct hmap_key) {.p = path}); 198 assert(link); 199 state = link->value._p; 200 201 linkp = hmap_link_pos(map, (struct hmap_key) {.p = path}); 202 if (!*linkp) { 203 key = memdup(path, sizeof(struct path)); 204 room = malloc(sizeof(struct room)); 205 memcpy(&room->path, path, sizeof(struct path)); 206 dvec_init(&room->items, sizeof(char *), 0, 207 &stdlib_strict_heap_allocator); 208 parse_output(out, &room->name, &room->doors, &room->items); 209 assert(room->name && room->doors); 210 211 *linkp = hmap_link_alloc(map, 212 (struct hmap_key) {.p = key}, 213 (struct hmap_val) {.p = room}, NULL); 214 215 if (!strcmp(room->name, "Pressure-Sensitive Floor")) { 216 assert(path->dircnt); 217 path->dircnt -= 1; 218 return path->dir[path->dircnt]; 219 } 220 221 for (DVEC_ITER(&room->items, name)) { 222 if (!strcmp(*name, "infinite loop")) 223 continue; 224 if (!strcmp(*name, "escape pod")) 225 continue; 226 if (!strcmp(*name, "photons")) 227 continue; 228 if (!strcmp(*name, "molten lava")) 229 continue; 230 if (!strcmp(*name, "giant electromagnet")) 231 continue; 232 *(char **)dvec_add_slot(items) = *name; 233 dvec_clear(in); 234 dvec_sprintf(in, "take %s\n", *name); 235 feed_input(icc, in); 236 read_output(icc, out); 237 } 238 } else { 239 room = (*linkp)->value._p; 240 } 241 242 assert(path->dircnt != sizeof(path->dir) - 1); 243 path->dircnt += 1; 244 for (dir = state->next; dir < 4; dir++) { 245 if (!(room->doors & (1 << dir))) 246 continue; 247 if (dir == state->back) 248 continue; 249 path->dir[path->dircnt - 1] = (uint8_t) dir; 250 link = hmap_get(map, (struct hmap_key) {.p = path}); 251 if (link) continue; 252 break; 253 } 254 state->next = (uint8_t) dir + 1; 255 path->dircnt -= 1; 256 257 if (dir >= 4) { 258 if (!path->dircnt) return -1; 259 path->dircnt -= 1; 260 261 dir = state->back; 262 } else { 263 path->dircnt += 1; 264 265 linkp = hmap_link_pos(states, (struct hmap_key) {.p = path}); 266 if (!*linkp) { 267 aoc_debug("add: %s\n", path_str(path)); 268 key = memdup(path, sizeof(struct path)); 269 state = malloc(sizeof(struct state)); 270 state->next = 0; 271 state->back = (dir + 2) % 4; 272 *linkp = hmap_link_alloc(states, 273 (struct hmap_key) {.p = key}, 274 (struct hmap_val) {.p = state}, NULL); 275 } 276 } 277 278 return (int) dir; 279} 280 281void 282input_from_dir(struct dvec *in, int dir) 283{ 284 dvec_clear(in); 285 switch (dir) { 286 case ADJ_NORTH: 287 dvec_add_slots(in, 7); 288 strcpy(in->data, "north\n"); 289 break; 290 case ADJ_EAST: 291 dvec_add_slots(in, 6); 292 strcpy(in->data, "east\n"); 293 break; 294 case ADJ_SOUTH: 295 dvec_add_slots(in, 7); 296 strcpy(in->data, "south\n"); 297 break; 298 case ADJ_WEST: 299 dvec_add_slots(in, 6); 300 strcpy(in->data, "west\n"); 301 break; 302 } 303} 304 305void 306get_path(struct hmap *map, struct path *path, const char *name) 307{ 308 struct hmap_iter iter; 309 struct room *room; 310 311 for (HMAP_ITER(map, iter)) { 312 room = iter.link->value._p; 313 if (!strcmp(room->name, name)) { 314 memcpy(path, &room->path, sizeof(struct path)); 315 return; 316 } 317 } 318 319 assert(0); 320} 321 322void 323move(struct icc *icc, struct dvec *in, struct dvec *out, int dir) 324{ 325 input_from_dir(in, dir); 326 feed_input(icc, in); 327 read_output(icc, out); 328} 329 330void 331move_to(struct icc *icc, struct dvec *in, struct dvec *out, struct path *path) 332{ 333 ssize_t i; 334 335 for (i = 0; i < path->dircnt; i++) 336 move(icc, in, out, path->dir[i]); 337} 338 339void 340move_back(struct icc *icc, struct dvec *in, struct dvec *out, struct path *path) 341{ 342 ssize_t i; 343 344 for (i = path->dircnt - 1; i >= 0; i--) 345 move(icc, in, out, path->dir[i]); 346} 347 348void 349interactive(struct icc *icc) 350{ 351 int c; 352 353 while (1) { 354 switch (icc->state) { 355 case ICC_INPUT: 356 c = getc(stdin); 357 if (c == 4) break; 358 mi_setv(&icc->in, (mi_ul) c, MI_POS); 359 break; 360 case ICC_OUTPUT: 361 c = (int) mi_cast_uls(&icc->out); 362 putc(c, stdout); 363 break; 364 case ICC_RUN: 365 break; 366 default: 367 assert(0); 368 } 369 icc_step_inst(icc); 370 if (icc->state == ICC_INPUT && c <= 4) 371 break; 372 } 373} 374 375bool 376find_items(struct icc *icc, struct dvec *in, struct dvec *out, 377 struct dvec *items, struct dvec *taken, size_t depth, int dir) 378{ 379 char **name, **other, **slot; 380 381 for (DVEC_ITER(items, name)) { 382 for (DVEC_ITER(taken, other)) { 383 if (!strcmp(*name, *other)) 384 break; 385 } 386 if (other) continue; 387 388 dvec_clear(in); 389 dvec_sprintf(in, "take %s\n", *name); 390 feed_input(icc, in); 391 read_output(icc, out); 392 393 input_from_dir(in, dir); 394 feed_input(icc, in); 395 read_output(icc, out); 396 397 slot = dvec_add_slot(taken); 398 *slot = *name; 399 400 for (DVEC_ITER(taken, other)) 401 aoc_debug("%s > ", *other); 402 403 if (strstr(out->data, "lighter")) { 404 aoc_debug("*lighter*\n"); 405 } else if (strstr(out->data, "heavier")) { 406 aoc_debug("*heavier*\n"); 407 if (depth != items->len) { 408 if (find_items(icc, in, out, 409 items, taken, depth + 1, dir)) 410 return true; 411 } 412 } else { 413 aoc_debug("*correct*\n"); 414 return true; 415 } 416 417 dvec_rm_slot(taken, slot); 418 419 dvec_clear(in); 420 dvec_sprintf(in, "drop %s\n", *name); 421 feed_input(icc, in); 422 read_output(icc, out); 423 } 424 425 return false; 426} 427 428void 429part1(void) 430{ 431 struct icc icc; 432 struct dvec in, out; 433 struct hmap map; 434 struct hmap states; 435 struct hmap_iter iter; 436 struct dvec items; 437 struct dvec taken; 438 struct room *room; 439 struct state *state; 440 struct path path; 441 struct path *key; 442 size_t answer; 443 char **name; 444 char *str; 445 int dir; 446 447 icc_init(&icc); 448 icc_parse_inst(&icc, aoc.input, aoc.input_size); 449 450 dvec_init(&in, 1, 0, &stdlib_strict_heap_allocator); 451 dvec_init(&out, 1, 0, &stdlib_strict_heap_allocator); 452 453 hmap_init(&map, 32, path_hmap_hash, path_hmap_keycmp, 454 &stdlib_strict_heap_allocator); 455 hmap_init(&states, 32, path_hmap_hash, path_hmap_keycmp, 456 &stdlib_strict_heap_allocator); 457 458 dvec_init(&items, sizeof(char *), 0, &stdlib_strict_heap_allocator); 459 dvec_init(&taken, sizeof(char *), 0, &stdlib_strict_heap_allocator); 460 461 path.dircnt = 0; 462 memset(path.dir, 0, DIR_COUNT); 463 464 key = memdup(&path, sizeof(struct path)); 465 state = malloc(sizeof(struct state)); 466 state->back = 4; 467 state->next = 0; 468 hmap_add(&states, (struct hmap_key) {.p = key}, 469 (struct hmap_val) {.p = state}); 470 471 if (getenv("INTERACTIVE")) { 472 interactive(&icc); 473 goto exit; 474 } 475 476 while (1) { 477 dir = explore(&icc, &in, &out, &states, 478 &map, &path, &items); 479 if (dir < 0) break; 480 input_from_dir(&in, dir); 481 feed_input(&icc, &in); 482 } 483 484 get_path(&map, &path, "Pressure-Sensitive Floor"); 485 path.dircnt -= 1; 486 move_to(&icc, &in, &out, &path); 487 488 for (DVEC_ITER(&items, name)) { 489 dvec_clear(&in); 490 dvec_sprintf(&in, "drop %s\n", *name); 491 feed_input(&icc, &in); 492 read_output(&icc, &out); 493 } 494 495 //interactive(&icc); 496 assert(find_items(&icc, &in, &out, &items, 497 &taken, 1, path.dir[path.dircnt])); 498 path.dircnt += 1; 499 500 str = strstr(out.data, "typing "); 501 assert(str != NULL); 502 assert(sscanf(str, "typing %lu on the keypad", &answer) == 1); 503 504 aoc.answer = aprintf("%lu", answer); 505 aoc.solution = "278664"; 506 507 for (HMAP_ITER(&map, iter)) { 508 room = iter.link->value._p; 509 aoc_debug("-- ROOM --\n"); 510 aoc_debug("path: %s\n", path_str(&room->path)); 511 aoc_debug("name: %s\n", room->name); 512 aoc_debug("doors: %04b\n", room->doors); 513 for (DVEC_ITER(&room->items, name)) 514 aoc_debug("- %s\n", *name); 515 aoc_debug("\n"); 516 } 517 518exit: 519 for (HMAP_ITER(&map, iter)) { 520 free(iter.link->key._p); 521 room = iter.link->value._p; 522 free(room->name); 523 for (DVEC_ITER(&room->items, name)) 524 free(*name); 525 dvec_deinit(&room->items); 526 free(room); 527 } 528 hmap_deinit(&map); 529 530 for (HMAP_ITER(&states, iter)) { 531 free(iter.link->key._p); 532 free(iter.link->value._p); 533 } 534 hmap_deinit(&states); 535 536 dvec_deinit(&taken); 537 dvec_deinit(&items); 538 539 dvec_deinit(&out); 540 dvec_deinit(&in); 541 542 icc_deinit(&icc); 543} 544 545void 546part2(void) 547{ 548 aoc.answer = strdup(""); 549 aoc.solution = ""; 550}