aoc-2019-c

Advent of Code 2019 Solutions in C
git clone https://git.sinitax.com/sinitax/aoc-2019-c
Log | Files | Refs | README | sfeed.txt

main.c (20982B)


      1#include "aoc.h"
      2#include "allocator.h"
      3#include "dvec_s.h"
      4#include "hmap.h"
      5#include "util.h"
      6#include "list.h"
      7#include "vec.h"
      8
      9#include <signal.h>
     10#include <assert.h>
     11#include <ctype.h>
     12#include <stdbool.h>
     13#include <stdint.h>
     14
     15struct state {
     16	struct vec2i pos;
     17	uint32_t acquired;
     18	size_t dist;
     19	struct list_link link;
     20};
     21
     22struct state_multi {
     23	struct vec2i pos[4];
     24	uint32_t acquired;
     25	size_t dist;
     26	struct list_link link;
     27};
     28
     29struct prog {
     30	uint32_t acquired;
     31	size_t dist;
     32};
     33
     34struct path {
     35	uint32_t required;
     36	size_t dist;
     37};
     38
     39struct keypath {
     40	uint32_t required;
     41	size_t dist;
     42	struct vec2i pos;
     43	uint32_t keymask;
     44	char key;
     45};
     46
     47struct node {
     48	struct dvec edges;
     49	int key;
     50};
     51
     52const struct vec2i dirs[] = {
     53	{  0, -1 },
     54	{  1,  0 },
     55	{  0,  1 },
     56	{ -1,  0 },
     57};
     58
     59static inline bool
     60bit_subset(uint32_t a, uint32_t b)
     61{
     62	return (a & b) == a;
     63}
     64
     65static inline bool
     66bit_proper_subset(uint32_t a, uint32_t b)
     67{
     68	return bit_subset(a, b) && (a < b);
     69}
     70
     71static inline bool
     72bit_superset(uint32_t a, uint32_t b)
     73{
     74	return (a & b) == b;
     75}
     76
     77static inline bool
     78bit_proper_superset(uint32_t a, uint32_t b)
     79{
     80	return bit_superset(a, b) && (a > b);
     81}
     82
     83bool
     84vec2i_hmap_keycmp(struct hmap_key k1, struct hmap_key k2)
     85{
     86	const struct vec2i *v1 = k1.p, *v2 = k2.p;
     87
     88	return vec2i_eql(v1, v2);
     89}
     90
     91uint32_t
     92vec2i_hmap_hash(struct hmap_key key)
     93{
     94	const struct vec2i *v = key.p;
     95
     96	return (uint32_t) v->x + (uint32_t) v->y * 80;
     97}
     98
     99bool
    100vec2i_multi_hmap_keycmp(struct hmap_key k1, struct hmap_key k2)
    101{
    102	const struct vec2i *v1 = k1.p, *v2 = k2.p;
    103	size_t i;
    104
    105	for (i = 0; i < 4; i++) {
    106		if (!vec2i_eql(&v1[i], &v2[i]))
    107			return false;
    108	}
    109
    110	return true;
    111}
    112
    113uint32_t
    114vec2i_multi_hmap_hash(struct hmap_key key)
    115{
    116	const struct vec2i *v = key.p;
    117	uint32_t hash;
    118	size_t i;
    119
    120	hash = 0;
    121	for (i = 0; i < 4; i++)
    122		hash += (uint32_t) v[i].x + (uint32_t) v[i].y * 80;
    123
    124	return hash;
    125}
    126
    127void
    128print_map(const struct hmap *map, struct hmap *distmap,
    129	const struct vec2i *start, uint32_t acquired)
    130{
    131	struct hmap_iter iter;
    132	struct hmap_link *link;
    133	struct vec2i min, max;
    134	struct vec2i pos;
    135	uint32_t mask;
    136	char c;
    137
    138	vec2i_set(&min, start);
    139	vec2i_set(&max, start);
    140	for (HMAP_ITER(map, iter)) {
    141		vec2i_set(&pos, iter.link->key._p);
    142		if (pos.x < min.x) min.x = pos.x;
    143		if (pos.y < min.y) min.y = pos.y;
    144		if (pos.x > max.x) max.x = pos.x;
    145		if (pos.y > max.y) max.y = pos.y;
    146	}
    147
    148	aoc_debug("+");
    149	for (pos.x = min.x; pos.x <= max.x; pos.x++)
    150		aoc_debug("-");
    151	aoc_debug("+\n");
    152
    153	for (pos.y = min.y; pos.y <= max.y; pos.y++) {
    154		aoc_debug("|");
    155		for (pos.x = min.x; pos.x <= max.x; pos.x++) {
    156			if (vec2i_eql(&pos, start)) {
    157				aoc_debug("\x1b[5m@\x1b[0m");
    158				continue;
    159			}
    160
    161			link = hmap_get(map, (struct hmap_key) {.p = &pos});
    162			if (link) {
    163				c = link->value.c;
    164				if (isalpha(c)) {
    165					mask = islower(c) ? 1 << (c - 'a')
    166						: 1 << (c - 'A');
    167					if (acquired & mask) {
    168						aoc_debug("\x1b[90m%c\x1b[0m", c);
    169					} else {
    170						aoc_debug("%c", c);
    171					}
    172					continue;
    173				}
    174
    175				link = hmap_get(distmap,
    176					(struct hmap_key) {.p = &pos});
    177				if (link) {
    178					aoc_debug(" ");
    179				} else {
    180					aoc_debug("%c", c);
    181				}
    182			} else {
    183				aoc_debug(" ");
    184			}
    185		}
    186		aoc_debug("|\n");
    187	}
    188
    189	aoc_debug("+");
    190	for (pos.x = min.x; pos.x <= max.x; pos.x++)
    191		aoc_debug("-");
    192	aoc_debug("+\n");
    193}
    194
    195void
    196parse_input(struct hmap *map, struct vec2i *start, size_t *keycnt)
    197{
    198	const char *lpos, *lend;
    199	const char *c;
    200	char line[256];
    201	struct vec2i pos;
    202	void *key;
    203
    204	*keycnt = 0;
    205
    206	lpos = aoc.input;
    207	lend = aoc.input + aoc.input_size;
    208	vec2i_setv(&pos, 0, 0);
    209	while (readtok(line, sizeof(line), '\n', &lpos, lend)) {
    210		pos.x = 0;
    211		for (c = line; *c; c++) {
    212			key = memdup(&pos, sizeof(struct vec2i));
    213			hmap_add(map, (struct hmap_key) {.p = key},
    214				(struct hmap_val) {.c = *c});
    215			if (islower(*c)) *keycnt += 1;
    216			if (*c == '@') vec2i_set(start, &pos);
    217			pos.x += 1;
    218		}
    219		pos.y += 1;
    220	}
    221}
    222
    223bool
    224update_paths(struct dvec *paths, size_t dist, uint32_t required)
    225{
    226	struct path *path;
    227
    228	for (DVEC_ITER(paths, path)) {
    229		if (dist < path->dist) {
    230			if (bit_subset(required, path->required)) {
    231				path->required = required;
    232				path->dist = dist;
    233				return true;
    234			}
    235		} else if (dist == path->dist) {
    236			if (bit_proper_subset(required, path->required)) {
    237				path->required = required;
    238				return true;
    239			}
    240		} else {
    241			if (bit_superset(required, path->required))
    242				return false;
    243		}
    244	}
    245
    246	path = dvec_add_slot(paths);
    247	path->dist = dist;
    248	path->required = required;
    249
    250	return true;
    251}
    252
    253void
    254add_node(struct hmap *graph, const struct hmap *map,
    255	const struct vec2i *start, int key)
    256{
    257	struct hmap_iter iter;
    258	struct dvec active, active_next;
    259	struct state state, *cstate, *nstate;
    260	struct dvec *paths;
    261	struct path *path;
    262	struct keypath *keypath;
    263	struct hmap_link *link, **linkp;
    264	struct hmap distmap;
    265	struct node *node;
    266	struct vec2i *pos;
    267	size_t i;
    268	char c;
    269
    270	/*
    271	 * - dijkstra from start pos
    272	 * - when we encounter a door, must have acquired corresponding key
    273	 * - distmap resolves to dvec of paths
    274	 * - only save new distance if less than all known paths
    275	 *   and/or path requires a subset of keys
    276	 *
    277	 * - loop over keys in generated distance map
    278	 * - add keys as edges to node
    279	 */
    280
    281	dvec_init(&active, sizeof(struct state), 10,
    282		&stdlib_strict_heap_allocator);
    283	dvec_init(&active_next, sizeof(struct state), 10,
    284		&stdlib_strict_heap_allocator);
    285	hmap_init(&distmap, 64, vec2i_hmap_hash, vec2i_hmap_keycmp,
    286		&stdlib_strict_heap_allocator);
    287
    288	cstate = dvec_add_slot(&active_next);
    289	vec2i_set(&cstate->pos, start);
    290	cstate->acquired = 0;
    291	cstate->dist = 0;
    292
    293	pos = memdup(start, sizeof(struct vec2i));
    294	paths = dvec_alloc(sizeof(struct path), 1,
    295		&stdlib_strict_heap_allocator, NULL);
    296	path = dvec_add_slot(paths);
    297	path->dist = 0;
    298	path->required = 0;
    299	hmap_add(&distmap, (struct hmap_key) {.p = pos},
    300		(struct hmap_val) {.p = paths});
    301
    302	while (!dvec_empty(&active_next)) {
    303		dvec_swap(&active, &active_next);
    304		dvec_clear(&active_next);
    305
    306		for (DVEC_ITER(&active, cstate)) {
    307			for (i = 0; i < ARRLEN(dirs); i++) {
    308				vec2i_add(&state.pos, &cstate->pos, &dirs[i]);
    309
    310				link = hmap_get(map,
    311					(struct hmap_key) {.p = &state.pos});
    312				assert(link != NULL);
    313				c = link->value.c;
    314				if (c == '#') continue;
    315
    316				state.dist = cstate->dist + 1;
    317				state.acquired = cstate->acquired;
    318				if (isupper(c)) /* need key for door */
    319					state.acquired |= (1U << (c - 'A'));
    320
    321				linkp = hmap_link_pos(&distmap,
    322					(struct hmap_key) {.p = &state.pos});
    323				if (*linkp) {
    324					paths = (*linkp)->value._p;
    325				} else {
    326					pos = memdup(&state.pos, sizeof(struct vec2i));
    327					paths = dvec_alloc(sizeof(struct path),
    328						1, &stdlib_strict_heap_allocator,
    329						NULL);
    330					*linkp = hmap_link_alloc(&distmap,
    331						(struct hmap_key) {.p = pos},
    332						(struct hmap_val) {.p = paths},
    333						NULL);
    334				}
    335
    336				if (update_paths(paths, state.dist, state.acquired)) {
    337					nstate = dvec_add_slot(&active_next);
    338					memcpy(nstate, &state, sizeof(struct state));
    339				}
    340			}
    341		}
    342	}
    343
    344	node = malloc(sizeof(struct node));
    345	node->key = key;
    346	dvec_init(&node->edges, sizeof(struct keypath), 1,
    347		&stdlib_strict_heap_allocator);
    348	for (HMAP_ITER(map, iter)) {
    349		c = iter.link->value.c;
    350		if (vec2i_eql(iter.link->key.p, start))
    351			continue;
    352		if (islower(c)) {
    353			link = hmap_get(&distmap, iter.link->key);
    354			if (!link) continue;
    355			pos = iter.link->key._p;
    356			for (DVEC_ITER(link->value.p, path)) {
    357				keypath = dvec_add_slot(&node->edges);
    358				keypath->key = c;
    359				keypath->keymask = 1U << (c - 'a');
    360				keypath->dist = path->dist;
    361				keypath->required = path->required;
    362				vec2i_set(&keypath->pos, iter.link->key.p);
    363			}
    364		}
    365	}
    366	pos = memdup(start, sizeof(struct vec2i));
    367	hmap_add(graph, (struct hmap_key) {.p = pos},
    368		(struct hmap_val) {.p = node});
    369
    370	if (aoc.debug == 2) {
    371		aoc_debug("add_node: %li %li\n", start->x, start->y);
    372		print_map(map, &distmap, start, 0);
    373		for (DVEC_ITER(&node->edges, keypath)) {
    374			aoc_debug("path: %c %3lu %032b\n", keypath->key,
    375				keypath->dist, keypath->required);
    376		}
    377		aoc_debug("\n");
    378	}
    379
    380	for (HMAP_ITER(&distmap, iter)) {
    381		free(iter.link->key._p);
    382		dvec_free(iter.link->value._p);
    383	}
    384	hmap_deinit(&distmap);
    385	dvec_deinit(&active_next);
    386	dvec_deinit(&active);
    387}
    388
    389void
    390gen_graph(struct hmap *graph, const struct hmap *map,
    391	const struct vec2i *start, size_t keycnt)
    392{
    393	struct hmap_iter iter;
    394
    395	add_node(graph, map, start, -1);
    396	for (HMAP_ITER(map, iter)) {
    397		if (islower(iter.link->value.c)) {
    398			add_node(graph, map, iter.link->key.p,
    399				iter.link->value.c - 'a');
    400		}
    401	}
    402}
    403
    404void
    405sort_edges(struct dvec *edges)
    406{
    407	struct keypath tmp, *a, *b;
    408	size_t i, k;
    409
    410	if (!edges->len) return;
    411	for (i = 0; i < edges->len - 1; i++) {
    412		for (k = 0; k < edges->len - 1; k++) {
    413			a = dvec_at(edges, k);
    414			b = dvec_at(edges, k + 1);
    415			if (a->dist > b->dist) {
    416				memcpy(&tmp, b, sizeof(struct keypath));
    417				memcpy(b, a, sizeof(struct keypath));
    418				memcpy(a, &tmp, sizeof(struct keypath));
    419			}
    420		}
    421	}
    422}
    423
    424struct prog *
    425update_progs(struct dvec *progs, size_t dist, uint32_t acquired)
    426{
    427	struct prog *prog;
    428
    429	for (DVEC_ITER(progs, prog)) {
    430		if (bit_superset(acquired, prog->acquired)) {
    431			if (dist < prog->dist) {
    432				prog->acquired = acquired;
    433				prog->dist = dist;
    434				return prog;
    435			} else if (dist == prog->dist) {
    436				if (acquired > prog->acquired) {
    437					prog->acquired = acquired;
    438					return prog;
    439				} else {
    440					return NULL;
    441				}
    442			}
    443		}
    444	}
    445
    446	prog = dvec_add_slot(progs);
    447	prog->dist = dist;
    448	prog->acquired = acquired;
    449
    450	return prog;
    451}
    452
    453struct state *
    454state_alloc(const struct vec2i *pos, size_t dist, uint32_t acquired)
    455{
    456	struct state *state;
    457
    458	state = malloc(sizeof(struct state));
    459	vec2i_set(&state->pos, pos);
    460	state->dist = dist;
    461	state->acquired = acquired;
    462	state->link = LIST_LINK_INIT;
    463
    464	return state;
    465}
    466
    467bool
    468state_dist_ordering(const void *p1, const void *p2, void *u)
    469{
    470	const struct state *s1 = p1, *s2 = p2;
    471
    472	return s1->dist < s2->dist;
    473}
    474
    475void
    476add_keys(struct list *active, struct hmap *graph,
    477	struct hmap *distmap, struct state *cstate, size_t keycnt)
    478{
    479	struct hmap_link *link, **linkp;
    480	struct state state, *nstate;
    481	struct keypath *keypath;
    482	struct dvec *progs;
    483	struct node *node;
    484	struct prog *prog;
    485	struct vec2i *pos;
    486
    487	link = hmap_get(graph, (struct hmap_key) {.p = &cstate->pos});
    488	assert(link != NULL);
    489	node = link->value._p;
    490
    491	for (DVEC_ITER(&node->edges, keypath)) {
    492		if (cstate->acquired & keypath->keymask)
    493			continue;
    494
    495		if (!bit_superset(cstate->acquired, keypath->required))
    496			continue;
    497
    498		vec2i_set(&state.pos, &keypath->pos);
    499		state.dist = cstate->dist + keypath->dist;
    500		state.acquired = cstate->acquired | keypath->keymask;
    501
    502		linkp = hmap_link_pos(distmap, (struct hmap_key) {.p = &state.pos});
    503		if (*linkp) {
    504			progs = (*linkp)->value._p;
    505		} else {
    506			pos = memdup(&state.pos, sizeof(struct vec2i));
    507			progs = dvec_alloc(sizeof(struct prog), 1,
    508				&stdlib_strict_heap_allocator, NULL);
    509			*linkp = hmap_link_alloc(distmap,
    510				(struct hmap_key) {.p = pos},
    511				(struct hmap_val) {.p = progs}, NULL);
    512		}
    513
    514		if ((prog = update_progs(progs, state.dist, state.acquired))) {
    515			aoc_debug("updated prog %i %i %032b %032b\n",
    516				prog->dist, state.dist, prog->acquired, state.acquired);
    517			nstate = state_alloc(&state.pos, state.dist, state.acquired);
    518			list_insert_sorted(active, &nstate->link,
    519				false, state_dist_ordering,
    520				LIST_OFFSET(struct state, link), NULL);
    521		}
    522	}
    523}
    524
    525size_t
    526min_dist_all_keys(struct hmap *graph, const struct vec2i *start, size_t keycnt)
    527{
    528	struct list_link *list_link;
    529	struct hmap_link *hmap_link;
    530	struct hmap_iter iter;
    531	struct hmap distmap;
    532	struct list active;
    533	struct state *cstate;
    534	struct dvec *progs;
    535	struct prog *prog;
    536	struct node *node;
    537	struct vec2i *pos;
    538	size_t mdist;
    539
    540	/*
    541	 * - dijkstra from starting node
    542	 * - only move over edges that we collected keys for
    543	 * - distmap resolves to dvec of progs
    544	 * - only save new distance if less than all known progs
    545	 *   and/or we have a superset of previous keys
    546	 * - if we reach key and have, save mindist
    547	 */
    548
    549	list_init(&active);
    550	hmap_init(&distmap, 256, vec2i_hmap_hash, vec2i_hmap_keycmp,
    551		&stdlib_strict_heap_allocator);
    552
    553	cstate = state_alloc(start, 0, 0);
    554	list_insert_back(&active, &cstate->link);
    555
    556	pos = memdup(start, sizeof(struct vec2i));
    557	progs = dvec_alloc(sizeof(struct prog), 1,
    558		&stdlib_strict_heap_allocator, NULL);
    559	prog = dvec_add_slot(progs);
    560	prog->acquired = 0;
    561	prog->dist = 0;
    562	hmap_add(&distmap, (struct hmap_key) {.p = pos},
    563		(struct hmap_val) {.p = progs});
    564
    565	for (HMAP_ITER(graph, iter)) {
    566		node = iter.link->value._p;
    567		sort_edges(&node->edges);
    568	}
    569
    570	mdist = 0;
    571	while (!list_empty(&active)) {
    572		list_link = list_front(&active);
    573		cstate = LIST_UPCAST(list_link, struct state, link);
    574		if (cstate->acquired == (1U << keycnt) - 1) {
    575			mdist = cstate->dist;
    576			goto exit;
    577		}
    578
    579		list_link_pop(list_link);
    580
    581		hmap_link = hmap_get(&distmap, (struct hmap_key) {.p = &cstate->pos});
    582		assert(link != NULL);
    583		for (DVEC_ITER(hmap_link->value.p, prog)) {
    584			if (prog->dist < cstate->dist) {
    585				if (bit_superset(prog->acquired,
    586						cstate->acquired))
    587					break;
    588			} else if (prog->dist == cstate->dist) {
    589				if (bit_proper_superset(prog->acquired,
    590						cstate->acquired))
    591					break;
    592			}
    593		}
    594		if (prog) {
    595			free(cstate);
    596			continue;
    597		}
    598
    599		aoc_debug("active %02li %02li %032b %lu\n",
    600			cstate->pos.x, cstate->pos.y,
    601			cstate->acquired, cstate->dist);
    602
    603		add_keys(&active, graph, &distmap, cstate, keycnt);
    604
    605		free(cstate);
    606	}
    607
    608exit:
    609	for (HMAP_ITER(&distmap, iter)) {
    610		free(iter.link->key._p);
    611		dvec_free(iter.link->value._p);
    612	}
    613	hmap_deinit(&distmap);
    614	list_free_items(&active, free, LIST_OFFSET(struct state, link));
    615
    616	return mdist;
    617}
    618
    619void
    620write_map(struct hmap *map, ssize_t x, ssize_t y, char c)
    621{
    622	struct hmap_link *hmap_link;
    623	struct vec2i pos;
    624
    625	vec2i_setv(&pos, x, y);
    626	hmap_link = hmap_get(map, (struct hmap_key) {.p = &pos});
    627	assert(hmap_link);
    628	hmap_link->value.c = c;
    629}
    630
    631struct state_multi *
    632state_multi_alloc(const struct vec2i *pos, size_t dist, uint32_t acquired)
    633{
    634	struct state_multi *state;
    635
    636	state = malloc(sizeof(struct state_multi));
    637	memcpy(state->pos, pos, 4 * sizeof(struct vec2i));
    638	state->dist = dist;
    639	state->acquired = acquired;
    640	state->link = LIST_LINK_INIT;
    641
    642	return state;
    643}
    644
    645bool
    646state_multi_dist_ordering(const void *p1, const void *p2, void *u)
    647{
    648	const struct state_multi *s1 = p1, *s2 = p2;
    649
    650	return s1->dist < s2->dist;
    651}
    652
    653void
    654add_keys_multi(struct list *active, struct hmap *graphs,
    655	struct hmap *distmap, struct state_multi *cstate, size_t keycnt)
    656{
    657	struct hmap_link *link, **linkp;
    658	struct state_multi state, *nstate;
    659	struct keypath *keypath;
    660	struct dvec *progs;
    661	struct node *node;
    662	struct prog *prog;
    663	struct vec2i *pos;
    664	size_t i;
    665
    666	for (i = 0; i < 4; i++) {
    667		link = hmap_get(&graphs[i], (struct hmap_key) {.p = &cstate->pos[i]});
    668		assert(link != NULL);
    669		node = link->value._p;
    670
    671		for (DVEC_ITER(&node->edges, keypath)) {
    672			if (cstate->acquired & keypath->keymask)
    673				continue;
    674
    675			if (!bit_subset(keypath->required, cstate->acquired))
    676				continue;
    677
    678			memcpy(state.pos, cstate->pos, 4 * sizeof(struct vec2i));
    679			vec2i_set(&state.pos[i], &keypath->pos);
    680			state.dist = cstate->dist + keypath->dist;
    681			state.acquired = cstate->acquired | keypath->keymask;
    682
    683			linkp = hmap_link_pos(distmap, (struct hmap_key) {.p = state.pos});
    684			if (*linkp) {
    685				aoc_debug("old\n");
    686				progs = (*linkp)->value._p;
    687			} else {
    688				pos = memdup(state.pos, sizeof(struct vec2i) * 4);
    689				progs = dvec_alloc(sizeof(struct prog), 1,
    690					&stdlib_strict_heap_allocator, NULL);
    691				*linkp = hmap_link_alloc(distmap,
    692					(struct hmap_key) {.p = pos},
    693					(struct hmap_val) {.p = progs}, NULL);
    694			}
    695
    696			if ((prog = update_progs(progs, state.dist, state.acquired))) {
    697				aoc_debug("update prog %li,%li %li,%li %li,%li %li,%li "
    698					"%i %i %032b %032b\n",
    699					state.pos[0].x, state.pos[0].y,
    700					state.pos[1].x, state.pos[1].y,
    701					state.pos[2].x, state.pos[2].y,
    702					state.pos[3].x, state.pos[3].y,
    703					prog->dist, state.dist,
    704					prog->acquired, state.acquired);
    705				nstate = state_multi_alloc(state.pos, state.dist, state.acquired);
    706				list_insert_sorted(active, &nstate->link,
    707					false, state_multi_dist_ordering,
    708					LIST_OFFSET(struct state_multi, link),
    709					NULL);
    710			}
    711		}
    712	}
    713}
    714
    715size_t
    716min_dist_all_keys_multi(struct hmap *graphs, const struct vec2i *starts, size_t keycnt)
    717{
    718	struct list_link *list_link;
    719	struct hmap_link *hmap_link;
    720	struct hmap_iter hmap_iter;
    721	struct hmap distmap;
    722	struct list active;
    723	struct state_multi *cstate;
    724	struct dvec *progs;
    725	struct prog *prog;
    726	struct node *node;
    727	struct vec2i *pos;
    728	size_t mdist;
    729	size_t i;
    730
    731	/*
    732	 * - dijkstra from starting node
    733	 * - only move over edges that we collected keys for
    734	 * - distmap resolves to dvec of progs
    735	 * - only save new distance if less than all known progs
    736	 *   and/or we have a superset of previous keys
    737	 * - if we reach key and have, save mindist
    738	 */
    739
    740	list_init(&active);
    741	hmap_init(&distmap, 256, vec2i_multi_hmap_hash, vec2i_multi_hmap_keycmp,
    742		&stdlib_strict_heap_allocator);
    743
    744	cstate = state_multi_alloc(starts, 0, 0);
    745	list_insert_back(&active, &cstate->link);
    746
    747	pos = memdup(starts, sizeof(struct vec2i) * 4);
    748	progs = dvec_alloc(sizeof(struct prog), 1,
    749		&stdlib_strict_heap_allocator, NULL);
    750	prog = dvec_add_slot(progs);
    751	prog->acquired = 0;
    752	prog->dist = 0;
    753	hmap_add(&distmap, (struct hmap_key) {.p = pos},
    754		(struct hmap_val) {.p = progs});
    755
    756	for (i = 0; i < 4; i++) {
    757		for (HMAP_ITER(&graphs[i], hmap_iter)) {
    758			node = hmap_iter.link->value._p;
    759			sort_edges(&node->edges);
    760		}
    761	}
    762
    763	mdist = 0;
    764	while (!list_empty(&active)) {
    765		list_link = list_front(&active);
    766		cstate = LIST_UPCAST(list_link, struct state_multi, link);
    767		if (cstate->acquired == (1U << keycnt) - 1) {
    768			mdist = cstate->dist;
    769			goto exit;
    770		}
    771
    772		list_link_pop(list_link);
    773
    774		hmap_link = hmap_get(&distmap, (struct hmap_key) {.p = cstate->pos});
    775		assert(hmap_link != NULL);
    776		for (DVEC_ITER(hmap_link->value.p, prog)) {
    777			if (prog->dist < cstate->dist) {
    778				if (bit_superset(prog->acquired,
    779						cstate->acquired))
    780					break;
    781			} else if (prog->dist == cstate->dist) {
    782				if (bit_proper_superset(prog->acquired,
    783						cstate->acquired))
    784					break;
    785			}
    786		}
    787		if (prog) {
    788			free(cstate);
    789			continue;
    790		}
    791
    792		aoc_debug("active %li,%li %li,%li %li,%li %li,%li %032b %li\n",
    793			cstate->pos[0].x, cstate->pos[0].y,
    794			cstate->pos[1].x, cstate->pos[1].y,
    795			cstate->pos[2].x, cstate->pos[2].y,
    796			cstate->pos[3].x, cstate->pos[3].y,
    797			cstate->acquired, cstate->dist);
    798
    799		add_keys_multi(&active, graphs, &distmap, cstate, keycnt);
    800
    801		free(cstate);
    802	}
    803
    804exit:
    805	for (HMAP_ITER(&distmap, hmap_iter)) {
    806		free(hmap_iter.link->key._p);
    807		dvec_free(hmap_iter.link->value._p);
    808	}
    809	hmap_deinit(&distmap);
    810	list_free_items(&active, free, LIST_OFFSET(struct state_multi, link));
    811
    812	return mdist;
    813}
    814
    815void
    816part1(void)
    817{
    818	struct hmap_iter iter;
    819	struct hmap map;
    820	struct hmap graph;
    821	struct vec2i start;
    822	struct node *node;
    823	size_t keycnt;
    824	size_t answer;
    825
    826	signal(SIGUSR1, exit);
    827
    828	hmap_init(&map, 256, vec2i_hmap_hash, vec2i_hmap_keycmp,
    829		&stdlib_strict_heap_allocator);
    830	hmap_init(&graph, 32, vec2i_hmap_hash, vec2i_hmap_keycmp,
    831		&stdlib_strict_heap_allocator);
    832
    833	parse_input(&map, &start, &keycnt);
    834
    835	gen_graph(&graph, &map, &start, keycnt);
    836
    837	answer = min_dist_all_keys(&graph, &start, keycnt);
    838	aoc.answer = aprintf("%lu", answer);
    839	aoc.solution = "5402";
    840
    841	for (HMAP_ITER(&graph, iter)) {
    842		free(iter.link->key._p);
    843		node = iter.link->value._p;
    844		dvec_deinit(&node->edges);
    845		free(node);
    846	}
    847	hmap_deinit(&graph);
    848
    849	for (HMAP_ITER(&map, iter))
    850		free(iter.link->key._p);
    851	hmap_deinit(&map);
    852}
    853
    854void
    855part2(void)
    856{
    857	struct hmap_iter hmap_iter;
    858	struct hmap map;
    859	struct hmap graphs[4];
    860	struct vec2i center;
    861	struct vec2i starts[4];
    862	struct node *node;
    863	size_t keycnt;
    864	size_t answer;
    865	size_t i;
    866
    867	signal(SIGUSR1, exit);
    868
    869	hmap_init(&map, 256, vec2i_hmap_hash, vec2i_hmap_keycmp,
    870		&stdlib_strict_heap_allocator);
    871
    872	parse_input(&map, &center, &keycnt);
    873
    874	write_map(&map, center.x - 1, center.y, '#');
    875	write_map(&map, center.x + 1, center.y, '#');
    876	write_map(&map, center.x, center.y - 1, '#');
    877	write_map(&map, center.x, center.y + 1, '#');
    878	write_map(&map, center.x, center.y, '#');
    879
    880	for (i = 0; i < 4; i++) {
    881		vec2i_add(&starts[i], &center, &dirs[i]);
    882		vec2i_add(&starts[i], &starts[i], &dirs[(i+1)%4]);
    883		hmap_init(&graphs[i], 32, vec2i_hmap_hash, vec2i_hmap_keycmp,
    884			&stdlib_strict_heap_allocator);
    885		gen_graph(&graphs[i], &map, &starts[i], keycnt);
    886	}
    887
    888	answer = min_dist_all_keys_multi(graphs, starts, keycnt);
    889	aoc.answer = aprintf("%lu", answer);
    890	aoc.solution = "2138";
    891
    892	for (i = 0; i < 4; i++) {
    893		for (HMAP_ITER(&graphs[i], hmap_iter)) {
    894			free(hmap_iter.link->key._p);
    895			node = hmap_iter.link->value._p;
    896			dvec_deinit(&node->edges);
    897			free(node);
    898		}
    899		hmap_deinit(&graphs[i]);
    900	}
    901
    902	for (HMAP_ITER(&map, hmap_iter))
    903		free(hmap_iter.link->key._p);
    904	hmap_deinit(&map);
    905}