#include "aoc.h" #include "allocator.h" #include "iccmp.h" #include "hmap.h" #include "util.h" #include #include #include #include struct vec2 { int x, y; }; struct panel { struct vec2 pos; int color; }; int black = 0, white = 1; /* counter clockwise dx dy */ struct vec2 dirs[] = { { 0, -1 }, /* up */ { 1, 0 }, /* right */ { 0, 1 }, /* down */ { -1, 0 } /* left */ }; const char *solmap = "\ .............................................\n\ .............................................\n\ ...#..#.###...##...##..####.#.....##..###....\n\ ...#..#.#..#.#..#.#..#.#....#....#..#.#..#...\n\ ...#..#.#..#.#....#..#.###..#....#....#..#...\n\ ...#..#.###..#....####.#....#....#....###....\n\ ...#..#.#.#..#..#.#..#.#....#....#..#.#......\n\ ....##..#..#..##..#..#.#....####..##..#......\ "; uint32_t hmap_pos_hash(struct hmap_key key) { const struct vec2 *vec = key.p; uint32_t hash; hash = (uint32_t) vec->x; hash |= ((uint32_t) vec->y) << 16; return hash; } bool hmap_pos_keycmp(struct hmap_key k1, struct hmap_key k2) { const struct vec2 *v1 = k1.p, *v2 = k2.p; return v1->x == v2->x && v1->y == v2->y; } char * gen_map(struct hmap *panels, struct vec2 *pos, int rot) { const char symbol[4] = "^>v<"; struct vec2 min, max, dims; struct hmap_iter iter; const struct vec2 *ppos; int i, color; char *map; min.x = min.y = -2; max.x = max.y = 2; for (HMAP_ITER(panels, iter)) { ppos = iter.link->key.p; min.x = MIN(min.x, ppos->x); min.y = MIN(min.y, ppos->y); max.x = MAX(max.x, ppos->x); max.y = MAX(max.y, ppos->y); } if (pos) { min.x = MIN(min.x, pos->x); min.y = MIN(min.y, pos->y); max.x = MAX(max.x, pos->x); max.y = MAX(max.y, pos->y); } dims.x = max.x - min.x + 1; dims.y = max.y - min.y + 1; assert(dims.x > 0 && dims.y > 0); map = malloc(((size_t) dims.x + 1) * (size_t) dims.y); assert(map != NULL); memset(map, '.', ((size_t) dims.x + 1) * (size_t) dims.y); for (HMAP_ITER(panels, iter)) { ppos = iter.link->key.p; color = iter.link->value.i; map[(ppos->y - min.y) * (dims.x + 1) + (ppos->x - min.x)] = color ? '#' : '.'; } if (pos) { map[(pos->y - min.y) * (dims.x + 1) + (pos->x - min.x)] = symbol[rot]; } for (i = 0; i < dims.y; i++) map[dims.x + i * (dims.x + 1)] = '\n'; map[(dims.x + 1) * dims.y - 1] = '\0'; return map; } void panels_init(struct hmap *panels, int start_color) { struct hmap_link **link; int color, rot, brot; struct vec2 pos; struct icc icc; void *key; char *map; enum { STATE_COLOR, STATE_ROTATE } state; icc_init(&icc); icc_parse_inst(&icc, aoc.input, aoc.input_size); pos.x = pos.y = 0; key = memdup(&pos, sizeof(pos)); hmap_add(panels, (struct hmap_key) {.p = key }, (struct hmap_val) {.i = start_color}); rot = 0; color = 0; state = STATE_COLOR; while (icc.state != ICC_HALT) { icc_step_inst(&icc); switch (icc.state) { case ICC_OUTPUT: if (state == STATE_COLOR) { color = (int) mi_cast_ul(&icc.out); assert(color == 0 || color == 1); aoc_debug("OUTPUT %i %i: %i\n", pos.x, pos.y, color); link = hmap_link_pos(panels, (struct hmap_key) {.p = &pos}); if (*link) { (*link)->value.i = color; } else { key = memdup(&pos, sizeof(pos)); *link = hmap_link_alloc(panels, (struct hmap_key) {.p = key}, (struct hmap_val) {.i = color}, NULL); } state = STATE_ROTATE; } else if (state == STATE_ROTATE) { brot = (int) mi_cast_ul(&icc.out); assert(brot == 0 || brot == 1); aoc_debug("ROT %i %i: %i\n", pos.x, pos.y, brot); rot = (rot + (brot ? 1 : -1) + 4) % 4; pos.x += dirs[rot].x; pos.y += dirs[rot].y; if (aoc.debug) { map = gen_map(panels, &pos, rot); aoc_debug("%s", map); free(map); } state = STATE_COLOR; } break; case ICC_INPUT: link = hmap_link_get(panels, (struct hmap_key) {.p = &pos}); if (link) { aoc_debug("INPUT %i %i: %i\n", pos.x, pos.y, (*link)->value.i); mi_setv(&icc.in, (mi_ul) (*link)->value.i, MI_POS); } else { aoc_debug("INPUT %i %i: 0\n", pos.x, pos.y); mi_setv(&icc.in, 0, MI_POS); } break; } } icc_deinit(&icc); } void part1(void) { struct hmap panels; struct hmap_iter iter; int count; hmap_init(&panels, 100, hmap_pos_hash, hmap_pos_keycmp, &stdlib_strict_heap_allocator); panels_init(&panels, black); count = 0; for (HMAP_ITER(&panels, iter)) count += 1; aoc.answer = aprintf("%i", count); aoc.solution = "2088"; for (HMAP_ITER(&panels, iter)) free(iter.link->key._p); hmap_deinit(&panels); } void part2(void) { struct hmap panels; struct hmap_iter iter; char *map; hmap_init(&panels, 100, hmap_pos_hash, hmap_pos_keycmp, &stdlib_strict_heap_allocator); panels_init(&panels, white); map = gen_map(&panels, NULL, 0); aoc.answer = map; aoc.solution = solmap; for (HMAP_ITER(&panels, iter)) free(iter.link->key._p); hmap_deinit(&panels); }