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