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 (4961B)


      1#include "aoc.h"
      2#include "util.h"
      3
      4#include <stdlib.h>
      5#include <stdio.h>
      6#include <string.h>
      7
      8#define MAXA(a, b) (ABS(a) > ABS(b) ? (a) : (b))
      9#define MINA(a, b) (ABS(a) > ABS(b) ? (b) : (a))
     10
     11struct line {
     12	int sx, sy;
     13	int ex, ey;
     14
     15	struct line *next;
     16};
     17
     18struct line *
     19parse_lines(const char **pos, const char *end)
     20{
     21	char buf[2048], part[64];
     22	const char *lpos, *lend;
     23	struct line *line, *start, **iter;
     24	int x, y, val;
     25
     26	aoc_debug("START\n");
     27
     28	if (!readtok(buf, sizeof(buf), '\n', pos, end))
     29		die("parse_lines: end of file");
     30
     31	start = line = NULL;
     32	iter = &line;
     33
     34	x = y = 0;
     35	lpos = buf;
     36	lend = buf + strlen(buf);
     37	while (readtok(part, sizeof(part), ',', &lpos, lend)) {
     38		*iter = line = malloc(sizeof(struct line));
     39		if (!line) die("parse_lines: oom");
     40
     41		if (!start) start = line;
     42
     43		line->next = NULL;
     44		line->sx = x;
     45		line->sy = y;
     46
     47		val = (int) parsei64(part+1);
     48		switch (part[0]) {
     49		case 'L':
     50			x -= val;
     51			break;
     52		case 'R':
     53			x += val;
     54			break;
     55		case 'D':
     56			y -= val;
     57			break;
     58		case 'U':
     59			y += val;
     60			break;
     61		default:
     62			die("parse_lines: invalid move: %s", part);
     63		}
     64
     65		aoc_debug("%i %i\n", x, y);
     66
     67		line->ex = x;
     68		line->ey = y;
     69
     70		iter = &(*iter)->next;
     71	}
     72
     73	aoc_debug("END\n");
     74
     75	return start;
     76}
     77
     78void
     79free_lines(struct line *line)
     80{
     81	struct line *next;
     82
     83	while (line) {
     84		next = line->next;
     85		free(line);
     86		line = next;
     87	}
     88}
     89
     90int
     91do_intersect(struct line *l1, struct line *l2)
     92{
     93	int inx, iny;
     94
     95	inx = MAX(l1->sx, l1->ex) >= MIN(l2->sx, l2->ex)
     96		&& MAX(l2->sx, l2->ex) >= MIN(l1->sx, l1->ex);
     97	iny = MAX(l1->sy, l1->ey) >= MIN(l2->sy, l2->ey)
     98		&& MAX(l2->sy, l2->ey) >= MIN(l1->sy, l1->ey);
     99
    100	return inx && iny;
    101}
    102
    103void
    104intersection_near_origin(struct line *l1, struct line *l2, int *x, int *y)
    105{
    106	if (l1->sx == l1->ex && l2->sx == l2->ex) {
    107		*x = l1->sx;
    108		*y = MAXA(
    109			MINA(l1->sy, l1->ey),
    110			MINA(l2->sy, l2->ey)
    111		);
    112	} else if (l1->sy == l1->ey && l2->sy == l2->ey) {
    113		*y = l1->sy;
    114		*x = MAXA(
    115			MINA(l1->sx, l1->ex),
    116			MINA(l2->sy, l2->ey)
    117		);
    118	} else {
    119		*x = (l1->sx == l1->ex) ? l1->sx : l2->sx;
    120		*y = (l1->sy == l1->ey) ? l1->sy : l2->sy;
    121	}
    122}
    123
    124void
    125intersection_least_steps(struct line *l1, struct line *l2, int *x, int *y)
    126{
    127	int in1, in2;
    128
    129	if (l1->sx == l1->ex && l2->sx == l2->ex) {
    130		/* if both ends or both starts of lines are part of the intersection,
    131		 * any one of them will give the same best dist,
    132		 * otherwise the start that intersects is the best fit */
    133		*x = l1->sx;
    134		in1 = l1->sy <= MAX(l2->sy, l2->ey) && l1->sy >= MIN(l2->sy, l2->ey);
    135		in2 = l2->sy <= MAX(l1->sy, l1->ey) && l2->sy >= MIN(l1->sy, l1->ey);
    136		*y = in1 ? l1->sy : (in2 ? l2->sy : l2->ey);
    137	} else if (l1->sy == l1->ey && l2->sy == l2->ey) {
    138		/* same for x-axis */
    139		*y = l1->sy;
    140		in1 = l1->sx <= MAX(l2->sx, l2->ex) && l1->sx >= MIN(l2->sx, l2->ex);
    141		in2 = l2->sx <= MAX(l1->sx, l1->ex) && l2->sx >= MIN(l1->sx, l1->ex);
    142		*x = in1 ? l1->sx : (in2 ? l2->sx : l2->ex);
    143	} else {
    144		*x = (l1->sx == l1->ex) ? l1->sx : l2->sx;
    145		*y = (l1->sy == l1->ey) ? l1->sy : l2->sy;
    146	}
    147}
    148
    149int
    150calc_dist(struct line *lines, struct line *end, int x, int y)
    151{
    152	struct line *iter;
    153	int dist;
    154
    155	dist = 0;
    156	for (iter = lines; iter != end; iter = iter->next) {
    157		dist += ABS(iter->ex - iter->sx);
    158		dist += ABS(iter->ey - iter->sy);
    159		aoc_debug("D: %i\n", dist);
    160	}
    161
    162	dist += ABS(x - iter->sx);
    163	dist += ABS(y - iter->sy);
    164	aoc_debug("D: %i\n", dist);
    165
    166	return dist;
    167}
    168
    169void
    170part1(void)
    171{
    172	struct line *lines1, *lines2;
    173	struct line *iter1, *iter2;
    174	const char *pos, *end;
    175	int nx, ny, hit;
    176	int x, y;
    177
    178	pos = aoc.input;
    179	end = aoc.input + aoc.input_size;
    180	lines1 = parse_lines(&pos, end);
    181	lines2 = parse_lines(&pos, end);
    182
    183	x = y = 0;
    184	for (iter1 = lines1; iter1; iter1 = iter1->next) {
    185		for (iter2 = lines2; iter2; iter2 = iter2->next) {
    186			hit = do_intersect(iter1, iter2);
    187			if (!hit) continue;
    188			intersection_near_origin(iter1, iter2, &nx, &ny);
    189			if (!x && !y || ABS(nx) + ABS(ny) < ABS(x) + ABS(y)) {
    190				x = nx;
    191				y = ny;
    192			}
    193		}
    194	}
    195
    196	aoc_debug("dist(%i, %i) = %i\n", x, y, ABS(x) + ABS(y));
    197	aoc.answer = aprintf("%i", ABS(x) + ABS(y));
    198	aoc.solution = "209";
    199
    200	free_lines(lines1);
    201	free_lines(lines2);
    202}
    203
    204void
    205part2(void)
    206{
    207	struct line *lines1, *lines2;
    208	struct line *iter1, *iter2;
    209	const char *pos, *end;
    210	int nx, ny, nd, hit;
    211	int x, y, d;
    212
    213	pos = aoc.input;
    214	end = aoc.input + aoc.input_size;
    215	lines1 = parse_lines(&pos, end);
    216	lines2 = parse_lines(&pos, end);
    217
    218	x = y = 0;
    219	for (iter1 = lines1; iter1; iter1 = iter1->next) {
    220		for (iter2 = lines2; iter2; iter2 = iter2->next) {
    221			hit = do_intersect(iter1, iter2);
    222			if (!hit) continue;
    223			intersection_least_steps(iter1, iter2, &nx, &ny);
    224			nd = calc_dist(lines1, iter1, nx, ny);
    225			nd += calc_dist(lines2, iter2, nx, ny);
    226			if (!x && !y || nd < d) {
    227				d = nd;
    228				x = nx;
    229				y = ny;
    230			}
    231		}
    232	}
    233
    234	aoc_debug("steps(%i, %i) = %i\n", x, y, d);
    235	aoc.answer = aprintf("%i", d);
    236	aoc.solution = "43258";
    237
    238	free_lines(lines1);
    239	free_lines(lines2);
    240}