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


      1#include "aoc.h"
      2#include "allocator.h"
      3#include "util.h"
      4#include "hmap.h"
      5
      6#include <math.h>
      7#include <assert.h>
      8#include <stdbool.h>
      9#include <stdio.h>
     10#include <stdlib.h>
     11
     12struct asteroid {
     13	int x, y;
     14
     15	struct asteroid *next;
     16};
     17
     18struct dir {
     19	int dx, dy;
     20};
     21
     22struct asteroid *asteroids;
     23int width, height;
     24
     25bool
     26hmap_dir_keycmp(struct hmap_key k1, struct hmap_key k2)
     27{
     28	const struct dir *d1 = k1.p, *d2 = k2.p;
     29
     30	return d1->dx == d2->dx && d1->dy == d2->dy;
     31}
     32
     33uint32_t
     34hmap_dir_hash(struct hmap_key key)
     35{
     36	const struct dir *dir = key.p;
     37	uint32_t hash;
     38
     39	hash = ((uint32_t) dir->dx & 0xFFFF);
     40	hash |= ((uint32_t) dir->dy & 0xFFFF) << 16;
     41
     42	return hash;
     43}
     44
     45void
     46add_asteroid(int x, int y)
     47{
     48	struct asteroid **iter;
     49
     50	for (iter = &asteroids; *iter; iter = &((*iter)->next));
     51
     52	*iter = malloc(sizeof(struct asteroid));
     53	assert(*iter != NULL);
     54	(*iter)->x = x;
     55	(*iter)->y = y;
     56	(*iter)->next = NULL;
     57}
     58
     59void
     60asteroids_init(void)
     61{
     62	char *p;
     63	int x, y;
     64
     65	asteroids = NULL;
     66	width = height = 0;
     67
     68	x = y = 0;
     69	for (p = aoc.input; *p; p++) {
     70		switch (*p) {
     71		case '\n':
     72			width = x;
     73			x = 0;
     74			height++;
     75			y++;
     76			break;
     77		case '#':
     78			add_asteroid(x, y);
     79		case '.':
     80			x++;
     81			break;
     82		}
     83	}
     84
     85	assert(width != 0 && height != 0);
     86}
     87
     88void
     89asteroids_deinit(void)
     90{
     91	struct asteroid *iter, *next;
     92
     93	for (iter = asteroids; iter; iter = next) {
     94		next = iter->next;
     95		free(iter);
     96	}
     97}
     98
     99int
    100gcd(int a, int b)
    101{
    102	int t;
    103
    104	while (b) {
    105		t = b;
    106		b = a % b;
    107		a = t;
    108	}
    109
    110	return a;
    111}
    112
    113void
    114reduce_frac(struct dir *d)
    115{
    116	int cd;
    117
    118	cd = gcd(ABS(d->dx), ABS(d->dy));
    119	d->dx /= cd;
    120	d->dy /= cd;
    121}
    122
    123void
    124get_vis(struct hmap *hm, const struct asteroid *a1)
    125{
    126	struct hmap_link *link;
    127	const struct asteroid *a2, *tmp;
    128	struct dir dir, odir;
    129	void *key;
    130	int rc;
    131
    132	for (a2 = asteroids; a2; a2 = a2->next) {
    133		if (a1 == a2) continue;
    134
    135		dir.dx = a2->x - a1->x;
    136		dir.dy = a2->y - a1->y;
    137		reduce_frac(&dir);
    138
    139		link = hmap_get(hm, (struct hmap_key) {.p = &dir});
    140		if (link) {
    141			tmp = link->value.p;
    142			odir = (struct dir) { tmp->x - a1->x, tmp->y - a1->y };
    143			dir = (struct dir) { a2->x - a1->x, a2->y - a1->y };
    144			if (ABS(odir.dx) + ABS(odir.dy) > ABS(dir.dx) + ABS(dir.dy))
    145				link->value.p = a2;
    146		} else {
    147			key = memdup(&dir, sizeof(struct dir));
    148			rc = hmap_add(hm, (struct hmap_key) {.p = key},
    149				(struct hmap_val) {.p = a2});
    150			assert(!rc);
    151		}
    152	}
    153}
    154
    155float
    156angle(const struct asteroid *a, const struct asteroid *base)
    157{
    158	if (a->x == base->x)
    159		return a->y > base->y ? 0 : -(float) 3.1415926;
    160
    161	return (float) atan2(base->x - a->x, a->y - base->y);
    162}
    163
    164void
    165find_base(const struct asteroid **a_out, int *vis_out)
    166{
    167	struct asteroid *a1, *cand;
    168	struct hmap_iter iter;
    169	struct hmap dirmap;
    170	int vis, maxvis;
    171
    172	hmap_init(&dirmap, 100, hmap_dir_hash, hmap_dir_keycmp,
    173		&stdlib_strict_heap_allocator);
    174
    175	maxvis = 0;
    176	cand = NULL;
    177	for (a1 = asteroids; a1; a1 = a1->next) {
    178		aoc_debug("Asteroid @ %i,%i => ", a1->x, a1->y);
    179		get_vis(&dirmap, a1);
    180
    181		vis = 0;
    182		for (HMAP_ITER(&dirmap, iter))
    183			vis++;
    184		aoc_debug("%i vis\n", vis);
    185
    186		if (maxvis == 0 || vis > maxvis) {
    187			maxvis = vis;
    188			cand = a1;
    189		}
    190
    191		for (HMAP_ITER(&dirmap, iter))
    192			free(iter.link->key._p);
    193		hmap_clear(&dirmap);
    194	}
    195
    196	assert(cand != NULL);
    197	hmap_deinit(&dirmap);
    198
    199	if (vis_out) *vis_out = maxvis;
    200	if (a_out) *a_out = cand;
    201}
    202
    203void
    204part1(void)
    205{
    206	const struct asteroid *a;
    207	int vis;
    208
    209	asteroids_init();
    210	find_base(&a, &vis);
    211
    212	aoc_debug("Best at %i,%i with %i vis\n", a->x, a->y, vis);
    213	aoc.answer = aprintf("%i", vis);
    214	aoc.solution = "299";
    215
    216	asteroids_deinit();
    217}
    218
    219void
    220part2(void)
    221{
    222	const struct asteroid *base, *tmp;
    223	struct hmap_iter iter;
    224	const struct asteroid **list;
    225	struct hmap dirmap;
    226	int i, k, len;
    227	float prev;
    228
    229	asteroids_init();
    230	find_base(&base, NULL);
    231
    232	hmap_init(&dirmap, 100, hmap_dir_hash, hmap_dir_keycmp,
    233		&stdlib_strict_heap_allocator);
    234	get_vis(&dirmap, base);
    235
    236	len = 0;
    237	for (HMAP_ITER(&dirmap, iter))
    238		len++;
    239	list = malloc(sizeof(struct asteroid *) * (size_t) len);
    240	assert(list != NULL);
    241	i = 0;
    242	for (HMAP_ITER(&dirmap, iter))
    243		list[i++] = iter.link->value.p;
    244
    245	for (i = 0; i < len; i++) {
    246		for (k = 0; k < len - 1; k++) {
    247			if (angle(list[k], base) > angle(list[k+1], base)) {
    248				tmp = list[k];
    249				list[k] = list[k+1];
    250				list[k+1] = tmp;
    251			}
    252		}
    253	}
    254
    255	prev = angle(list[0], base);
    256	for (k = 0; k < len; k++) {
    257		aoc_debug("%i: %i %i %f\n", k+1, list[k]->x,
    258			list[k]->y, angle(list[k], base));
    259	}
    260
    261	aoc.answer = aprintf("%i", list[199]->x * 100 + list[199]->y);
    262	aoc.solution = "1419";
    263
    264	free(list);
    265
    266	for (HMAP_ITER(&dirmap, iter))
    267		free(iter.link->key._p);
    268
    269	asteroids_deinit();
    270	hmap_deinit(&dirmap);
    271}