main.c (12699B)
1#include "aoc.h" 2#include "allocator.h" 3#include "util.h" 4#include "iccmp.h" 5#include "hmap.h" 6#include "dvec_s.h" 7#include "vec.h" 8 9#include <assert.h> 10#include <stdbool.h> 11#include <stddef.h> 12#include <stdio.h> 13#include <stdlib.h> 14 15enum { 16 DIR_NORTH, 17 DIR_EAST, 18 DIR_SOUTH, 19 DIR_WEST, 20}; 21 22struct path { 23 struct vec2i start, end; 24}; 25 26static const struct vec2i dirs[] = { 27 [DIR_NORTH] = { 0, -1 }, 28 [DIR_EAST] = { 1, 0 }, 29 [DIR_SOUTH] = { 0, 1 }, 30 [DIR_WEST] = { -1, 0 }, 31}; 32 33bool 34vec2i_hmap_keycmp(struct hmap_key k1, struct hmap_key k2) 35{ 36 const struct vec2i *v1 = k1.p, *v2 = k2.p; 37 38 return v1->x == v2->x && v1->y == v2->y; 39} 40 41uint32_t 42vec2i_hmap_hash(struct hmap_key key) 43{ 44 const struct vec2i *v = key.p; 45 46 return (uint32_t) (v->x << 16) ^ (uint32_t) v->y; 47} 48 49int 50dir_from_char(char c) 51{ 52 switch (c) { 53 case '^': 54 return DIR_NORTH; 55 case '>': 56 return DIR_EAST; 57 case 'v': 58 return DIR_SOUTH; 59 case '<': 60 return DIR_WEST; 61 default: 62 return -1; 63 } 64} 65 66int 67dir_from_path(struct path *path) 68{ 69 if (path->end.x > path->start.x) 70 return DIR_EAST; 71 else if (path->end.x < path->start.x) 72 return DIR_WEST; 73 else if (path->end.y > path->start.y) 74 return DIR_SOUTH; 75 else if (path->end.y < path->start.y) 76 return DIR_NORTH; 77 assert(0); 78} 79 80void 81receive_map(struct icc *icc, struct hmap *map, 82 struct vec2i *min, struct vec2i *max, 83 struct vec2i *dpos, int *ddir) 84{ 85 struct hmap_iter iter; 86 struct vec2i pos; 87 void *key; 88 char c; 89 90 for (HMAP_ITER(map, iter)) 91 free(iter.link->key._p); 92 hmap_clear(map); 93 94 vec2i_setv(min, 0, 0); 95 vec2i_setv(max, 0, 0); 96 vec2i_setv(&pos, 0, 0); 97 while (icc->state != ICC_HALT) { 98 icc_step_inst(icc); 99 if (icc->state == ICC_INPUT) 100 break; 101 if (icc->state == ICC_OUTPUT) { 102 c = (char) mi_cast_ul(&icc->out); 103 if (c == '\n') { 104 if (pos.x == 0) break; 105 pos.y += 1; 106 pos.x = 0; 107 } else { 108 if (dir_from_char(c) >= 0) { 109 vec2i_set(dpos, &pos); 110 *ddir = dir_from_char(c); 111 } 112 key = memdup(&pos, sizeof(struct vec2i)); 113 hmap_add(map, (struct hmap_key) {.p = key}, 114 (struct hmap_val) {.c = c}); 115 if (pos.x > max->x) max->x = pos.x; 116 if (pos.y > max->y) max->y = pos.y; 117 if (pos.x < min->x) min->x = pos.x; 118 if (pos.y < min->y) min->y = pos.y; 119 pos.x += 1; 120 } 121 } 122 } 123} 124 125void 126receive_output(struct icc *icc) 127{ 128 aoc_debug("ICC> "); 129 while (icc->state != ICC_HALT) { 130 icc_step_inst(icc); 131 if (icc->state == ICC_INPUT) 132 break; 133 if (icc->state == ICC_OUTPUT) 134 aoc_debug("%c", (char) mi_cast_ul(&icc->out)); 135 } 136 assert(icc->state != ICC_HALT); 137} 138 139void 140print_map(struct hmap *map, struct vec2i min, struct vec2i max) 141{ 142 struct hmap_link *link; 143 struct vec2i pos; 144 145 aoc_debug("+"); 146 for (pos.x = min.x; pos.x <= max.x; pos.x++) 147 aoc_debug("-"); 148 aoc_debug("+\n"); 149 150 for (pos.y = min.y; pos.y <= max.y; pos.y++) { 151 aoc_debug("|"); 152 for (pos.x = min.x; pos.x <= max.x; pos.x++) { 153 link = hmap_get(map, (struct hmap_key) {.p = &pos}); 154 if (link) aoc_debug("%c", link->value.c); 155 else aoc_debug(" "); 156 } 157 aoc_debug("|\n"); 158 } 159 160 aoc_debug("+"); 161 for (pos.x = min.x; pos.x <= max.x; pos.x++) 162 aoc_debug("-"); 163 aoc_debug("+\n"); 164} 165 166void 167find_path_end(struct hmap *map, struct vec2i start, 168 size_t dir, struct vec2i *end) 169{ 170 struct hmap_link *link; 171 struct vec2i ppos, pos; 172 173 vec2i_set(&pos, &start); 174 while (1) { 175 vec2i_set(&ppos, &pos); 176 vec2i_add(&pos, &pos, &dirs[dir]); 177 link = hmap_get(map, (struct hmap_key) {.p = &pos}); 178 if (!link || link->value.c != '#') 179 break; 180 } 181 182 vec2i_set(end, &ppos); 183} 184 185void 186add_path(struct hmap *paths, struct path *path) 187{ 188 struct hmap_link **link; 189 struct dvec *list; 190 void *key; 191 192 link = hmap_link_pos(paths, (struct hmap_key) {.p = &path->start}); 193 if (*link) { 194 list = (*link)->value._p; 195 memcpy(dvec_add_slot(list), path, sizeof(struct path)); 196 } else { 197 key = memdup(&path->start, sizeof(struct vec2i)); 198 list = dvec_alloc(sizeof(struct path), 199 1, &stdlib_strict_heap_allocator, NULL); 200 memcpy(dvec_add_slot(list), path, sizeof(struct path)); 201 hmap_add(paths, 202 (struct hmap_key) {.p = key}, 203 (struct hmap_val) {.p = list}); 204 } 205} 206 207void 208gen_paths(struct hmap *paths, struct hmap *map, 209 struct vec2i min, struct vec2i max) 210{ 211 struct hmap_link *link; 212 struct vec2i pos, npos; 213 struct vec2i end; 214 struct path path; 215 bool side[4]; 216 bool endpoint; 217 size_t i; 218 219 vec2i_setv(&pos, 0, 0); 220 for (pos.y = min.y; pos.y <= max.y; pos.y++) { 221 for (pos.x = min.x; pos.x <= max.x; pos.x++) { 222 link = hmap_get(map, (struct hmap_key) {.p = &pos}); 223 if (!link || link->value.c == '.') 224 continue; 225 226 for (i = 0; i < ARRLEN(dirs); i++) { 227 side[i] = false; 228 vec2i_add(&npos, &pos, &dirs[i]); 229 link = hmap_get(map, (struct hmap_key) {.p = &npos}); 230 side[i] = link ? link->value.c == '#' : false; 231 } 232 233 endpoint = (side[DIR_NORTH] != side[DIR_SOUTH]); 234 endpoint |= (side[DIR_WEST] != side[DIR_EAST]); 235 if (endpoint) { 236 aoc_debug("node %li %li\n", pos.x, pos.y); 237 for (i = 0; i < ARRLEN(dirs); i++) { 238 if (!side[i]) continue; 239 find_path_end(map, pos, i, &end); 240 vec2i_set(&path.start, &pos); 241 vec2i_set(&path.end, &end); 242 add_path(paths, &path); 243 } 244 } 245 } 246 } 247} 248 249void 250gen_insts(struct dvec *insts, struct hmap *paths, 251 struct vec2i start, int ddir) 252{ 253 struct hmap_link *link; 254 struct dvec *list; 255 struct path *path; 256 struct vec2i ppos, pos; 257 char *inst, type; 258 int cnt, dir, ndir; 259 bool found; 260 261 dir = ddir; 262 vec2i_set(&pos, &start); 263 vec2i_set(&ppos, &pos); 264 while (1) { 265 link = hmap_get(paths, (struct hmap_key) {.p = &pos}); 266 assert(link != NULL); 267 268 found = false; 269 list = link->value._p; 270 for (DVEC_ITER(list, path)) { 271 if (vec2i_eql(&ppos, &path->end)) 272 continue; 273 found = true; 274 break; 275 } 276 277 if (!found) break; 278 279 aoc_debug("path %i %i -> %i %i\n", path->start.x, path->start.y, 280 path->end.x, path->end.y); 281 282 vec2i_set(&ppos, &pos); 283 vec2i_set(&pos, &path->end); 284 285 ndir = dir_from_path(path); 286 aoc_debug("ndir %i\n", ndir); 287 type = ndir > dir ? 'R' : 'L'; 288 cnt = ABS(ndir - dir); 289 if (cnt > 2) { 290 cnt = 4 - cnt; 291 type = type == 'L' ? 'R' : 'L'; 292 } 293 for (; cnt > 0; cnt--) { 294 inst = dvec_add_slot(insts); 295 *inst = type; 296 } 297 dir = ndir; 298 299 cnt = (int) ABS(path->end.x - path->start.x) 300 + (int) ABS(path->end.y - path->start.y); 301 inst = dvec_add_slot(insts); 302 *inst = (char) -cnt; 303 } 304} 305 306char * 307insts_line(struct dvec *insts) 308{ 309 char *str; 310 char *c; 311 312 str = NULL; 313 for (DVEC_ITER(insts, c)) { 314 if (str) str = apprintf(str, ","); 315 if (*c < 0) { 316 str = apprintf(str, "%i", -*c); 317 } else { 318 str = apprintf(str, "%c", *c); 319 } 320 } 321 str = apprintf(str, "\n"); 322 323 return str; 324} 325 326size_t 327gen_func(struct dvec *insts, struct dvec *main, 328 struct dvec *cur, char cc, size_t start, size_t len, 329 struct dvec *f1, char c1, struct dvec *f2, char c2) 330{ 331 char *inst; 332 size_t i; 333 334 for (i = start; i < MIN(insts->len, start + len); i++) { 335 inst = dvec_add_slot(cur); 336 *inst = *(char *)dvec_at(insts, i); 337 } 338 339 inst = dvec_add_slot(main); 340 *inst = cc; 341 342 while (1) { 343 if (f1 && i + f1->len <= insts->len 344 && !memcmp(dvec_at(insts, i), f1->data, f1->len)) { 345 i += f1->len; 346 inst = dvec_add_slot(main); 347 *inst = c1; 348 } else if (f2 && i + f2->len <= insts->len 349 && !memcmp(dvec_at(insts, i), f2->data, f2->len)) { 350 i += f2->len; 351 inst = dvec_add_slot(main); 352 *inst = c2; 353 } else if (i + cur->len <= insts->len 354 && !memcmp(dvec_at(insts, i), cur->data, cur->len)) { 355 i += cur->len; 356 inst = dvec_add_slot(main); 357 *inst = cc; 358 } else { 359 break; 360 } 361 } 362 363 return i; 364} 365 366void 367gen_funcs(struct dvec *insts, struct dvec *main, 368 struct dvec *fa, struct dvec *fb, struct dvec *fc) 369{ 370 size_t alen, blen, clen; 371 size_t lens, pos; 372 char *line; 373 374 lens = 0; 375 while (lens < 20 * 20 * 20) { 376 dvec_clear(main); 377 dvec_clear(fa); 378 dvec_clear(fb); 379 dvec_clear(fc); 380 381 lens += 1; 382 alen = (lens / 20 / 20) % 20; 383 blen = (lens / 20) % 20; 384 clen = lens % 20; 385 if (!alen || !blen || !clen) 386 continue; 387 388 pos = 0; 389 pos = gen_func(insts, main, fa, 'A', pos, alen, NULL, 0, NULL, 0); 390 pos = gen_func(insts, main, fb, 'B', pos, blen, fa, 'A', NULL, 0); 391 pos = gen_func(insts, main, fc, 'C', pos, clen, fa, 'A', fb, 'B'); 392 393 assert(fa->len == alen); 394 assert(fb->len == blen); 395 assert(fc->len == clen); 396 397 if (aoc.debug && main->len > 3) { 398 line = insts_line(main); 399 aoc_debug("%2li %2li | %2li %2li %2li %s", 400 pos, insts->len, alen, blen, clen, line); 401 free(line); 402 403 line = insts_line(insts); 404 aoc_debug("%s", line); 405 free(line); 406 407 line = insts_line(fa); 408 aoc_debug("%s", line); 409 free(line); 410 411 line = insts_line(fb); 412 aoc_debug("%s", line); 413 free(line); 414 415 line = insts_line(fc); 416 aoc_debug("%s", line); 417 free(line); 418 419 aoc_debug("\n"); 420 } 421 422 if (pos == insts->len && main->len <= 20) 423 return; 424 } 425 assert(0); 426} 427 428void 429send_line(struct icc *icc, const char *line) 430{ 431 const char *c; 432 433 c = line; 434 while (icc->state != ICC_HALT && *c) { 435 icc_step_inst(icc); 436 switch (icc->state) { 437 case ICC_HALT: 438 case ICC_RUN: 439 continue; 440 case ICC_INPUT: 441 mi_setv(&icc->in, (mi_ul) *c, MI_POS); 442 c += 1; 443 break; 444 default: 445 receive_output(icc); 446 assert(0); 447 } 448 } 449 assert(icc->state != ICC_HALT); 450} 451 452void 453part1(void) 454{ 455 struct icc icc; 456 struct hmap map; 457 struct hmap_link *link; 458 struct hmap_iter iter; 459 struct vec2i pos, npos; 460 struct vec2i min, max; 461 struct vec2i dpos; 462 size_t answer; 463 size_t i; 464 int ddir; 465 466 icc_init(&icc); 467 hmap_init(&map, 32, vec2i_hmap_hash, vec2i_hmap_keycmp, 468 &stdlib_strict_heap_allocator); 469 470 icc_parse_inst(&icc, aoc.input, aoc.input_size); 471 472 receive_map(&icc, &map, &min, &max, &dpos, &ddir); 473 474 if (aoc.debug) 475 print_map(&map, min, max); 476 477 vec2i_setv(&pos, 0, 0); 478 answer = 0; 479 for (pos.y = min.y; pos.y <= max.y; pos.y++) { 480 for (pos.x = min.x; pos.x <= max.x; pos.x++) { 481 link = hmap_get(&map, (struct hmap_key) {.p = &pos}); 482 if (!link || link->value.c == '.') 483 continue; 484 for (i = 0; i < ARRLEN(dirs); i++) { 485 vec2i_add(&npos, &pos, &dirs[i]); 486 link = hmap_get(&map, (struct hmap_key) {.p = &npos}); 487 if (!link || link->value.c != '#') 488 break; 489 } 490 if (i == ARRLEN(dirs)) 491 answer += (size_t) pos.x * (size_t) pos.y; 492 } 493 } 494 495 aoc.answer = aprintf("%lu", answer); 496 aoc.solution = "4112"; 497 498 for (HMAP_ITER(&map, iter)) 499 free(iter.link->key._p); 500 hmap_deinit(&map); 501 icc_deinit(&icc); 502} 503 504void 505part2(void) 506{ 507 struct icc icc; 508 struct hmap map; 509 struct hmap paths; 510 struct dvec insts; 511 struct dvec main; 512 struct dvec fa, fb, fc; 513 struct hmap_iter iter; 514 struct vec2i min, max; 515 struct vec2i dpos; 516 struct maxint mi_addr = MI_INIT; 517 struct maxint mi_val = MI_INIT; 518 mi_ul ul_addr, ul_val; 519 char *line, buf[256]; 520 int ddir; 521 522 icc_init(&icc); 523 hmap_init(&map, 32, vec2i_hmap_hash, vec2i_hmap_keycmp, 524 &stdlib_strict_heap_allocator); 525 hmap_init(&paths, 32, vec2i_hmap_hash, vec2i_hmap_keycmp, 526 &stdlib_strict_heap_allocator); 527 dvec_init(&insts, sizeof(char), 32, &stdlib_strict_heap_allocator); 528 dvec_init(&main, sizeof(char), 0, &stdlib_strict_heap_allocator); 529 dvec_init(&fa, sizeof(char), 0, &stdlib_strict_heap_allocator); 530 dvec_init(&fb, sizeof(char), 0, &stdlib_strict_heap_allocator); 531 dvec_init(&fc, sizeof(char), 0, &stdlib_strict_heap_allocator); 532 533 icc_parse_inst(&icc, aoc.input, aoc.input_size); 534 535 icc_write(&icc, mi_imm(&mi_addr, &ul_addr, 0, MI_POS), 536 mi_imm(&mi_val, &ul_val, 2, MI_POS)); 537 538 receive_map(&icc, &map, &min, &max, &dpos, &ddir); 539 540 if (aoc.debug) 541 print_map(&map, min, max); 542 543 gen_paths(&paths, &map, min, max); 544 545 gen_insts(&insts, &paths, dpos, ddir); 546 547 if (aoc.debug) { 548 aoc_debug("%li insts\n", insts.len); 549 line = insts_line(&insts); 550 aoc_debug("%s", line); 551 free(line); 552 } 553 554 gen_funcs(&insts, &main, &fa, &fb, &fc); 555 556 receive_output(&icc); 557 line = insts_line(&main); 558 if (aoc.debug) printf("main %s", line); 559 send_line(&icc, line); 560 free(line); 561 562 receive_output(&icc); 563 line = insts_line(&fa); 564 if (aoc.debug) printf("A %s", line); 565 send_line(&icc, line); 566 free(line); 567 568 receive_output(&icc); 569 line = insts_line(&fb); 570 if (aoc.debug) printf("B %s", line); 571 send_line(&icc, line); 572 free(line); 573 574 receive_output(&icc); 575 line = insts_line(&fc); 576 if (aoc.debug) printf("C %s", line); 577 send_line(&icc, line); 578 free(line); 579 580 receive_output(&icc); 581 send_line(&icc, "n\n"); 582 583 while (icc.state != ICC_HALT) 584 icc_step_inst(&icc); 585exit: 586 mi_dec(&icc.out, buf, sizeof(buf), 0); 587 aoc.answer = aprintf("%s", buf); 588 aoc.solution = "578918"; 589 590 dvec_deinit(&fc); 591 dvec_deinit(&fb); 592 dvec_deinit(&fa); 593 dvec_deinit(&main); 594 dvec_deinit(&insts); 595 596 for (HMAP_ITER(&paths, iter)) { 597 free(iter.link->key._p); 598 dvec_free(iter.link->value._p); 599 } 600 hmap_deinit(&paths); 601 602 for (HMAP_ITER(&map, iter)) 603 free(iter.link->key._p); 604 hmap_deinit(&map); 605 606 icc_deinit(&icc); 607}