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

part1.c (6140B)


      1#include "allocator.h"
      2#include "aoc.h"
      3#include "hmap.h"
      4#include "hmap_s.h"
      5#include "vec_s.h"
      6#include "util.h"
      7#include "list.h"
      8
      9#include <assert.h>
     10#include <ctype.h>
     11#include <stdbool.h>
     12#include <stdint.h>
     13#include <stdlib.h>
     14
     15#define PORTAL_ID(a, b) ((size_t) ((uint8_t) (a) * 100 + (uint8_t) (b)))
     16
     17struct djk_state {
     18	size_t dist;
     19	struct vec2i pos;
     20
     21	struct list_link link;
     22};
     23
     24static bool
     25djk_dist_ordering(const void *p1, const void *p2, void *u)
     26{
     27	const struct djk_state *s1 = p1, *s2 = p2;
     28
     29	return s1->dist < s2->dist;
     30}
     31
     32static void
     33load_map(struct hmap *map, const char *input, size_t len)
     34{
     35	char line[256];
     36	const char *lpos, *lend;
     37	struct vec2i pos, *key;
     38
     39	lpos = aoc.input;
     40	lend = lpos + aoc.input_size;
     41	vec2i_setv(&pos, 0, 0);
     42	while (readtok(line, sizeof(line), '\n', &lpos, lend)) {
     43		for (pos.x = 0; line[pos.x]; pos.x++) {
     44			if (line[pos.x] == ' ')
     45				continue;
     46			key = malloc(sizeof(struct vec2i));
     47			vec2i_set(key, &pos);
     48			hmap_add(map, (struct hmap_key) {.p = key},
     49				(struct hmap_val) {.c = line[pos.x]});
     50		}
     51		pos.y += 1;
     52	}
     53}
     54
     55static void
     56load_portals(struct hmap *portals, struct hmap *map)
     57{
     58	struct hmap_link *link1;
     59	struct hmap_link *link2;
     60	struct hmap_iter iter;
     61	struct vec2i pos;
     62	struct vec2i npos;
     63	struct vec2i *key;
     64	size_t i, id;
     65
     66	for (HMAP_ITER(map, iter)) {
     67		if (!isupper(iter.link->value.c))
     68			continue;
     69
     70		vec2i_set(&pos, iter.link->key.p);
     71		for (i = 0; i < 4; i++) {
     72			vec2i_add(&npos, &pos, &adj[i]);
     73			link1 = hmap_get(map, (struct hmap_key) {.p = &npos});
     74			if (link1 && isupper(link1->value.c))
     75				break;
     76		}
     77		if (i != ADJ_SOUTH && i != ADJ_EAST)
     78			continue;
     79
     80		for (i = 0; i < 4; i++) {
     81			vec2i_add(&npos, &pos, &adj[i]);
     82			link2 = hmap_get(map, (struct hmap_key) {.p = &npos});
     83			if (link2 && link2->value.c == '.')
     84				break;
     85		}
     86		if (i == 4) {
     87			for (i = 0; i < 4; i++) {
     88				vec2i_add(&npos, link1->key.p, &adj[i]);
     89				link2 = hmap_get(map, (struct hmap_key) {.p = &npos});
     90				if (link2 && link2->value.c == '.')
     91					break;
     92			}
     93		}
     94		assert(i != 4);
     95
     96		aoc_debug("FOUND %c %c\n", iter.link->value.c, link1->value.c);
     97
     98		key = memdup(link2->key.p, sizeof(struct vec2i));
     99		id = PORTAL_ID(iter.link->value.c, link1->value.c);
    100		hmap_add(portals, (struct hmap_key) {.p = key},
    101			(struct hmap_val) {.s = id});
    102	}
    103}
    104
    105static bool
    106get_portal(struct hmap *portals, struct vec2i *pos, struct vec2i *skip, size_t id)
    107{
    108	struct hmap_iter iter;
    109
    110	for (HMAP_ITER(portals, iter)) {
    111		if (skip && vec2i_eql(skip, iter.link->key.p))
    112			continue;
    113		if (iter.link->value.s == id) {
    114			vec2i_set(pos, iter.link->key.p);
    115			return true;
    116		}
    117	}
    118
    119	return false;
    120}
    121
    122static void
    123add_djk_state(struct list *active, struct hmap *distmap,
    124	struct hmap *portals, struct vec2i *pos, size_t dist)
    125{
    126	struct hmap_link **hmap_linkp;
    127	struct djk_state *nstate;
    128	struct vec2i *key;
    129	bool new;
    130
    131	hmap_linkp = hmap_link_pos(distmap, (struct hmap_key) {.p = pos});
    132	if (!*hmap_linkp) {
    133		key = memdup(pos, sizeof(struct vec2i));
    134		*hmap_linkp = hmap_link_alloc(distmap,
    135			(struct hmap_key) {.p = key},
    136			(struct hmap_val) {.s = dist}, NULL);
    137		new = true;
    138	} else {
    139		if (dist < (*hmap_linkp)->value.s) {
    140			(*hmap_linkp)->value.s = dist;
    141			new = true;
    142		} else {
    143			new = false;
    144		}
    145	}
    146
    147	if (new) {
    148		nstate = malloc(sizeof(struct djk_state));
    149		nstate->dist = dist;
    150		vec2i_set(&nstate->pos, pos);
    151		nstate->link = LIST_LINK_INIT;
    152		list_insert_sorted(active, &nstate->link,
    153			false, djk_dist_ordering,
    154			LIST_OFFSET(struct djk_state, link), NULL);
    155	}
    156}
    157
    158static size_t
    159min_dist(struct hmap *map, struct hmap *portals,
    160	struct vec2i *start, struct vec2i *end)
    161{
    162	struct list active;
    163	struct hmap distmap;
    164	struct list_link *list_link;
    165	struct hmap_link *hmap_link;
    166	struct hmap_iter hmap_iter;
    167	struct djk_state *state;
    168	struct vec2i *key, npos;
    169	size_t mdist, i;
    170
    171	list_init(&active);
    172	hmap_init(&distmap, 256, vec2i_hmap_hash, vec2i_hmap_keycmp,
    173		&stdlib_strict_heap_allocator);
    174
    175	state = malloc(sizeof(struct djk_state));
    176	state->dist = 0;
    177	vec2i_set(&state->pos, start);
    178	list_insert_front(&active, &state->link);
    179
    180	key = memdup(start, sizeof(struct vec2i));
    181	hmap_add(&distmap, (struct hmap_key) {.p = key},
    182		(struct hmap_val) {.s = 0});
    183
    184	mdist = 0;
    185	while (!list_empty(&active)) {
    186		list_link = list_front(&active);
    187		state = LIST_UPCAST(list_link, struct djk_state, link);
    188		if (vec2i_eql(&state->pos, end)) {
    189			mdist = state->dist;
    190			goto exit;
    191		}
    192
    193		list_link_pop(list_link);
    194
    195		hmap_link = hmap_get(&distmap, (struct hmap_key) {.p = &state->pos});
    196		assert(hmap_link);
    197		if (state->dist != hmap_link->value.s) {
    198			free(state);
    199			continue;
    200		}
    201
    202		hmap_link = hmap_get(portals, (struct hmap_key) {.p = &state->pos});
    203		if (hmap_link) {
    204			if (get_portal(portals, &npos, &state->pos, hmap_link->value.s))
    205				add_djk_state(&active, &distmap, portals,
    206					&npos, state->dist + 1);
    207		}
    208
    209		for (i = 0; i < 4; i++) {
    210			vec2i_add(&npos, &state->pos, &adj[i]);
    211			hmap_link = hmap_get(map, (struct hmap_key) {.p = &npos});
    212			if (!hmap_link || hmap_link->value.c != '.') continue;
    213			add_djk_state(&active, &distmap, portals,
    214				&npos, state->dist + 1);
    215		}
    216
    217		free(state);
    218	}
    219
    220exit:
    221	for (HMAP_ITER(&distmap, hmap_iter))
    222		free(hmap_iter.link->key._p);
    223	hmap_deinit(&distmap);
    224	list_free_items(&active, free, LIST_OFFSET(struct djk_state, link));
    225
    226	return mdist;
    227}
    228
    229void
    230part1(void)
    231{
    232	struct hmap map;
    233	struct hmap portals;
    234	struct hmap_iter iter;
    235	struct vec2i start, end;
    236	size_t answer;
    237
    238	hmap_init(&map, 256, vec2i_hmap_hash, vec2i_hmap_keycmp,
    239		&stdlib_strict_heap_allocator);
    240	hmap_init(&portals, 256, vec2i_hmap_hash, vec2i_hmap_keycmp,
    241		&stdlib_strict_heap_allocator);
    242
    243	load_map(&map, aoc.input, aoc.input_size);
    244	load_portals(&portals, &map);
    245
    246	assert(get_portal(&portals, &start, NULL, PORTAL_ID('A', 'A')));
    247	assert(get_portal(&portals, &end, NULL, PORTAL_ID('Z', 'Z')));
    248	answer = min_dist(&map, &portals, &start, &end);
    249
    250	aoc.answer = aprintf("%lu", answer);
    251	aoc.solution = "656";
    252
    253	for (HMAP_ITER(&portals, iter))
    254		free(iter.link->key._p);
    255	hmap_deinit(&portals);
    256	for (HMAP_ITER(&map, iter))
    257		free(iter.link->key._p);
    258	hmap_deinit(&map);
    259}