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 (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}