aoc-2019-c

git clone https://git.sinitax.com/sinitax/aoc-2019-c
Log | Files | Refs | README | sfeed.txt

commit 46c71563e0f52a64d3f88cff120701db947383a4
parent a17aa0ba3f116c495aa76e79c449fa80d96c766a
Author: Louis Burda <quent.burda@gmail.com>
Date:   Wed, 10 Nov 2021 01:47:56 +0100

Add day 10 and modified hashmap implementation

Diffstat:
Mlibs/include/hashmap.h | 5+++--
Mlibs/src/hashmap.c | 57++++++++++++++++++++++++++++++++-------------------------
Msrc/06/main.c | 6+++++-
Asrc/10/Makefile | 12++++++++++++
Asrc/10/input | 39+++++++++++++++++++++++++++++++++++++++
Asrc/10/main.c | 247+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/10/part1 | 130+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/10/part2 | 92+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/10/test.input | 20++++++++++++++++++++
9 files changed, 580 insertions(+), 28 deletions(-)

diff --git a/libs/include/hashmap.h b/libs/include/hashmap.h @@ -31,11 +31,12 @@ struct hashmap { }; void hashmap_init(struct hashmap *hm, int size, uint32_t (*hasher)(void *key, int len)); +void hashmap_clear(struct hashmap *hm); void hashmap_free(struct hashmap *hm); void hashmap_set(struct hashmap *hm, struct hashmap_key key, void *value); -void * hashmap_get(struct hashmap *hm, struct hashmap_key key); -void * hashmap_pop(struct hashmap *hm, struct hashmap_key key); +int hashmap_get(struct hashmap *hm, struct hashmap_key key, struct hashmap_link **dst); +int hashmap_pop(struct hashmap *hm, struct hashmap_key key, struct hashmap_link **dst); struct hashmap_iter hashmap_iter(void); int hashmap_next(struct hashmap *hm, struct hashmap_iter *next); diff --git a/libs/src/hashmap.c b/libs/src/hashmap.c @@ -11,7 +11,7 @@ hashmap_init(struct hashmap *hm, int size, uint32_t (*hasher)(void *key, int len } void -hashmap_free(struct hashmap *hm) +hashmap_clear(struct hashmap *hm) { struct hashmap_iter iter; struct hashmap_link *prev; @@ -24,26 +24,19 @@ hashmap_free(struct hashmap *hm) prev = iter.link; } free(prev); - free(hm->buckets); - hm->buckets = NULL; + memset(hm->buckets, 0, hm->size * sizeof(struct hashmap_link *)); } void -hashmap_set(struct hashmap *hm, struct hashmap_key key, void *value) +hashmap_free(struct hashmap *hm) { - struct hashmap_link **iter; - - iter = &hm->buckets[hm->hash(key.key, key.len) % hm->size]; - while (*iter) iter = &((*iter)->next); - - *iter = CHKP(malloc(sizeof(struct hashmap_link))); - (*iter)->key = key; - (*iter)->value = value; - (*iter)->next = NULL; + hashmap_clear(hm); + free(hm->buckets); + hm->buckets = NULL; } -void * -hashmap_get(struct hashmap *hm, struct hashmap_key key) +int +hashmap_get(struct hashmap *hm, struct hashmap_key key, struct hashmap_link **dst) { struct hashmap_link **iter; struct hashmap_key ckey; @@ -51,34 +44,48 @@ hashmap_get(struct hashmap *hm, struct hashmap_key key) iter = &hm->buckets[hm->hash(key.key, key.len) % hm->size]; while (*iter) { ckey = (*iter)->key; - if (ckey.len == key.len && !memcmp(ckey.key, key.key, key.len)) - return (*iter)->value; + if (ckey.len == key.len && !memcmp(ckey.key, key.key, key.len)) { + if (dst) *dst = *iter; + return 1; + } iter = &((*iter)->next); } - return NULL; + return 0; } -void * -hashmap_pop(struct hashmap *hm, struct hashmap_key key) +int +hashmap_pop(struct hashmap *hm, struct hashmap_key key, struct hashmap_link **dst) { struct hashmap_link **iter; struct hashmap_key ckey; - void *value; iter = &hm->buckets[hm->hash(key.key, key.len) % hm->size]; while (*iter) { ckey = (*iter)->key; if (ckey.len == key.len && !memcmp(ckey.key, key.key, key.len)) { *iter = (*iter)->next; - value = (*iter)->value; - free(*iter); - return value; + if (dst) *dst = *iter; + return 1; } iter = &((*iter)->next); } - return NULL; + return 0; +} + +void +hashmap_set(struct hashmap *hm, struct hashmap_key key, void *value) +{ + struct hashmap_link **iter; + + iter = &hm->buckets[hm->hash(key.key, key.len) % hm->size]; + while (*iter) iter = &((*iter)->next); + + *iter = CHKP(malloc(sizeof(struct hashmap_link))); + (*iter)->key = key; + (*iter)->value = value; + (*iter)->next = NULL; } struct hashmap_iter diff --git a/src/06/main.c b/src/06/main.c @@ -18,7 +18,11 @@ struct hashmap planets; struct planet * get_planet(const char *name) { - return hashmap_get(&planets, HASHMAP_KEY(name, strlen(name))); + struct hashmap_link *link; + int status; + + status = hashmap_get(&planets, HASHMAP_KEY(name, strlen(name)), &link); + return status ? link->value : NULL; } struct planet * diff --git a/src/10/Makefile b/src/10/Makefile @@ -0,0 +1,12 @@ +CFLAGS = -g -I ../../libs/include -L ../../libs/build +LDLIBS = -laoc -lm + +all: lib main + +clean: + rm main + +lib: + make -C ../../libs + +main: main.c ../../libs/build/libaoc.a diff --git a/src/10/input b/src/10/input @@ -0,0 +1,39 @@ +.............#..#.#......##........#..# +.#...##....#........##.#......#......#. +..#.#.#...#...#...##.#...#............. +.....##.................#.....##..#.#.# +......##...#.##......#..#.......#...... +......#.....#....#.#..#..##....#....... +...................##.#..#.....#.....#. +#.....#.##.....#...##....#####....#.#.. +..#.#..........#..##.......#.#...#....# +...#.#..#...#......#..........###.#.... +##..##...#.#.......##....#.#..#...##... +..........#.#....#.#.#......#.....#.... +....#.........#..#..##..#.##........#.. +........#......###..............#.#.... +...##.#...#.#.#......#........#........ +......##.#.....#.#.....#..#.....#.#.... +..#....#.###..#...##.#..##............# +...##..#...#.##.#.#....#.#.....#...#..# +......#............#.##..#..#....##.... +.#.#.......#..#...###...........#.#.##. +........##........#.#...#.#......##.... +.#.#........#......#..........#....#... +...............#...#........##..#.#.... +.#......#....#.......#..#......#....... +.....#...#.#...#...#..###......#.##.... +.#...#..##................##.#......... +..###...#.......#.##.#....#....#....#.# +...#..#.......###.............##.#..... +#..##....###.......##........#..#...#.# +.#......#...#...#.##......#..#......... +#...#.....#......#..##.............#... +...###.........###.###.#.....###.#.#... +#......#......#.#..#....#..#.....##.#.. +.##....#.....#...#.##..#.#..##.......#. +..#........#.......##.##....#......#... +##............#....#.#.....#........... +........###.............##...#........# +#.........#.....#..##.#.#.#..#....#.... +..............##.#.#.#...........#..... diff --git a/src/10/main.c b/src/10/main.c @@ -0,0 +1,247 @@ +#include "aoc.h" +#include "hashmap.h" + +#include <stdlib.h> +#include <stdio.h> +#include <math.h> + +struct asteroid { + int x, y; + + struct asteroid *next; +}; + +struct dir { + int dx, dy; +}; + +struct asteroid *asteroids; +int width, height; + +uint32_t +dir_hasher(void *dp, int len) +{ + struct dir *d; + uint32_t hash; + + d = dp; + hash = ((uint16_t) d->dx & 0xFFFF); + hash |= ((uint16_t) d->dy & 0xFFFF) << 16; + + return hash; +} + +void +add_asteroid(int x, int y) +{ + struct asteroid **iter; + + for (iter = &asteroids; *iter; iter = &((*iter)->next)); + + *iter = CHKP(malloc(sizeof(struct asteroid))); + (*iter)->x = x; + (*iter)->y = y; + (*iter)->next = NULL; +} + +void +asteroids_init(void) +{ + char *p; + int x, y; + + asteroids = NULL; + width = height = 0; + + x = y = 0; + for (p = aoc.input; *p; p++) { + switch (*p) { + case '\n': + width = x; + x = 0; + height++; + y++; + break; + case '#': + add_asteroid(x, y); + case '.': + x++; + break; + } + } + + ASSERT(width != 0 && height != 0); +} + +void +asteroids_free(void) +{ + struct asteroid *iter, *next; + + for (iter = asteroids; iter; iter = next) { + next = iter->next; + free(iter); + } +} + +int +gcd(int a, int b) +{ + int t; + + while (b) { + t = b; + b = a % b; + a = t; + } + + return a; +} + +void +reduce_frac(struct dir *d) +{ + int cd; + + cd = gcd(ABS(d->dx), ABS(d->dy)); + d->dx /= cd; + d->dy /= cd; +} + +void +get_vis(struct hashmap *hm, struct asteroid *a1) +{ + struct hashmap_key key; + struct hashmap_link *link; + struct asteroid *a2, *tmp; + struct dir dir, odir, *dira; + + for (a2 = asteroids; a2; a2 = a2->next) { + if (a1 == a2) continue; + + dir.dx = a2->x - a1->x; + dir.dy = a2->y - a1->y; + reduce_frac(&dir); + + if (hashmap_get(hm, HASHMAP_KEY(&dir, sizeof(dir)), &link)) { + tmp = link->value; + odir = (struct dir) { tmp->x - a1->x, tmp->y - a1->y }; + dir = (struct dir) { a2->x - a1->x, a2->y - a1->y }; + if (ABS(odir.dx) + ABS(odir.dy) > ABS(dir.dx) + ABS(dir.dy)) + link->value = a2; + } else { + key = HASHMAP_KEY(CHKP(memdup(&dir, sizeof(dir))), sizeof(dir)); + hashmap_set(hm, key, a2); + } + } +} + +float +angle(struct asteroid *a, struct asteroid *base) +{ + double ang; + + if (a->x == base->x) + return a->y > base->y ? 0 : -M_PI; + return atan2(base->x - a->x, a->y - base->y); +} + +void +find_base(struct asteroid **a_out, int *vis_out) +{ + struct asteroid *a1, *cand; + struct hashmap_iter iter; + struct hashmap dirmap; + int vis, maxvis; + + hashmap_init(&dirmap, 100, dir_hasher); + + maxvis = 0; + for (a1 = asteroids; a1; a1 = a1->next) { + debug("Asteroid @ %i,%i => ", a1->x, a1->y); + get_vis(&dirmap, a1); + + vis = 0; + iter = hashmap_iter(); + while (hashmap_next(&dirmap, &iter)) + vis++; + + debug("%i vis\n", vis); + if (maxvis == 0 || vis > maxvis) { + maxvis = vis; + cand = a1; + } + + hashmap_clear(&dirmap); + } + + ASSERT(cand != NULL); + hashmap_free(&dirmap); + + if (vis_out) *vis_out = maxvis; + if (a_out) *a_out = cand; +} + +void +part1(void) +{ + struct asteroid *a; + int vis; + + asteroids_init(); + find_base(&a, &vis); + + debug("Best at %i,%i with %i vis\n", a->x, a->y, vis); + aoc.answer = CHKP(aprintf("%i", vis)); + aoc.solution = "299"; + + asteroids_free(); +} + +void +part2(void) +{ + struct asteroid *base, *tmp; + struct hashmap_iter iter; + struct asteroid **list; + struct hashmap dirmap; + float prev, ang; + int i, k, len; + + asteroids_init(); + find_base(&base, NULL); + + hashmap_init(&dirmap, 100, dir_hasher); + get_vis(&dirmap, base); + + len = 0; + iter = hashmap_iter(); + while (hashmap_next(&dirmap, &iter)) + len++; + + list = CHKP(malloc(sizeof(struct asteroid *) * len)); + + iter = hashmap_iter(); + for (i = 0; hashmap_next(&dirmap, &iter); i++) + list[i] = iter.link->value; + + for (i = 0; i < len; i++) { + for (k = 0; k < len - 1; k++) { + if (angle(list[k], base) > angle(list[k+1], base)) { + tmp = list[k]; + list[k] = list[k+1]; + list[k+1] = tmp; + } + } + } + + prev = angle(list[0], base); + for (k = 0; k < len; k++) { + debug("%i: %i %i %f\n", k+1, list[k]->x, list[k]->y, angle(list[k], base)); + } + + aoc.answer = CHKP(aprintf("%i", list[199]->x * 100 + list[199]->y)); + + asteroids_free(); + hashmap_free(&dirmap); +} diff --git a/src/10/part1 b/src/10/part1 @@ -0,0 +1,130 @@ +--- Day 10: Monitoring Station --- + +You fly into the asteroid belt and reach the Ceres monitoring station. The Elves here have an +emergency: they're having trouble tracking all of the asteroids and can't be sure they're safe. + +The Elves would like to build a new monitoring station in a nearby area of space; they hand you a +map of all of the asteroids in that region (your puzzle input). + +The map indicates whether each position is empty (.) or contains an asteroid (#). The asteroids are +much smaller than they appear on the map, and every asteroid is exactly in the center of its marked +position. The asteroids can be described with X,Y coordinates where X is the distance from the left +edge and Y is the distance from the top edge (so the top-left corner is 0,0 and the position +immediately to its right is 1,0). + +Your job is to figure out which asteroid would be the best place to build a new monitoring +station. A monitoring station can detect any asteroid to which it has +direct line of sight - that is, there cannot be another asteroid exactly +between them. This line of sight can be at any angle, not just lines aligned to the grid or +diagonally. The best location is the asteroid that can detect the largest +number of other asteroids. + +For example, consider the following map: + +.#..# +..... +##### +....# +...## + +The best location for a new monitoring station on this map is the highlighted asteroid at 3,4 +because it can detect 8 asteroids, more than any other location. (The only asteroid it cannot detect +is the one at 1,0; its view of this asteroid is blocked by the asteroid at 2,2.) All other asteroids +are worse locations; they can detect 7 or fewer other asteroids. Here is the number of other +asteroids a monitoring station on each asteroid could detect: + +.7..7 +..... +67775 +....7 +...87 + +Here is an asteroid (#) and some examples of the ways its line of sight might be blocked. If there +were another asteroid at the location of a capital letter, the locations marked with the +corresponding lowercase letter would be blocked and could not be detected: + +#......... +...A...... +...B..a... +.EDCG....a +..F.c.b... +.....c.... +..efd.c.gb +.......c.. +....f...c. +...e..d..c + +Here are some larger examples: + + + - Best is 5,8 with 33 other asteroids detected: + +......#.#. +#..#.#.... +..#######. +.#.#.###.. +.#..#..... +..#....#.# +#..#....#. +.##.#..### +##...#..#. +.#....#### + + + - Best is 1,2 with 35 other asteroids detected: + +#.#...#.#. +.###....#. +.#....#... +##.#.#.#.# +....#.#.#. +.##..###.# +..#...##.. +..##....## +......#... +.####.###. + + + - Best is 6,3 with 41 other asteroids detected: + +.#..#..### +####.###.# +....###.#. +..###.##.# +##.##.#.#. +....###..# +..#.#..#.# +#..#.#.### +.##...##.# +.....#.#.. + + + - Best is 11,13 with 210 other asteroids detected: + +.#..##.###...####### +##.############..##. +.#.######.########.# +.###.#######.####.#. +#####.##.#.##.###.## +..#####..#.######### +#################### +#.####....###.#.#.## +##.################# +#####.##.###..####.. +..######..##.####### +####.##.####...##..# +.#####..#.######.### +##...#.##########... +#.##########.####### +.####.#.###.###.#.## +....##.##.###..##### +.#.#.###########.### +#.#.#.#####.####.### +###.##.####.##.#..## + + + +Find the best location for a new monitoring station. How many other asteroids can be +detected from that location? + + diff --git a/src/10/part2 b/src/10/part2 @@ -0,0 +1,92 @@ +--- Part Two --- + +Once you give them the coordinates, the Elves quickly deploy an Instant Monitoring Station to the +location and discover the worst: there are simply too many asteroids. + +The only solution is complete vaporization by giant laser. + +Fortunately, in addition to an asteroid scanner, the new monitoring station also comes equipped with +a giant rotating laser perfect for vaporizing asteroids. The laser starts by pointing +up and always rotates clockwise, vaporizing any asteroid it hits. + +If multiple asteroids are exactly in line with the station, the laser only has enough +power to vaporize one of them before continuing its rotation. In other words, the same +asteroids that can be detected can be vaporized, but if vaporizing one asteroid makes +another one detectable, the newly-detected asteroid won't be vaporized until the laser has returned +to the same position by rotating a full 360 degrees. + +For example, consider the following map, where the asteroid with the new monitoring station (and +laser) is marked X: + +.#....#####...#.. +##...##.#####..## +##...#...#.#####. +..#.....X...###.. +..#.#.....#....## + +The first nine asteroids to get vaporized, in order, would be: + +.#....###24...#.. +##...##.13#67..9# +##...#...5.8####. +..#.....X...###.. +..#.#.....#....## + +Note that some asteroids (the ones behind the asteroids marked 1, 5, and 7) won't have a chance to +be vaporized until the next full rotation. The laser continues rotating; the next nine to be +vaporized are: + +.#....###.....#.. +##...##...#.....# +##...#......1234. +..#.....X...5##.. +..#.9.....8....76 + +The next nine to be vaporized are then: + +.8....###.....#.. +56...9#...#.....# +34...7........... +..2.....X....##.. +..1.............. + +Finally, the laser completes its first full rotation (1 through 3), a second rotation (4 through 8), +and vaporizes the last asteroid (9) partway through its third rotation: + +......234.....6.. +......1...5.....7 +................. +........X....89.. +................. + +In the large example above (the one with the best monitoring station location at 11,13): + + + - The 1st asteroid to be vaporized is at 11,12. + + - The 2nd asteroid to be vaporized is at 12,1. + + - The 3rd asteroid to be vaporized is at 12,2. + + - The 10th asteroid to be vaporized is at 12,8. + + - The 20th asteroid to be vaporized is at 16,0. + + - The 50th asteroid to be vaporized is at 16,9. + + - The 100th asteroid to be vaporized is at 10,16. + + - The 199th asteroid to be vaporized is at 9,6. + + - The 200th asteroid to be vaporized is at 8,2. + + - The 201st asteroid to be vaporized is at 10,9. + + - The 299th and final asteroid to be vaporized is at 11,1. + + +The Elves are placing bets on which will be the 200th asteroid to be vaporized. Win +the bet by determining which asteroid that will be; what do you get if you multiply its X +coordinate by 100 and then add its Y coordinate? (For example, 8,2 becomes 802.) + + diff --git a/src/10/test.input b/src/10/test.input @@ -0,0 +1,20 @@ +.#..##.###...####### +##.############..##. +.#.######.########.# +.###.#######.####.#. +#####.##.#.##.###.## +..#####..#.######### +#################### +#.####....###.#.#.## +##.################# +#####.##.###..####.. +..######..##.####### +####.##.####...##..# +.#####..#.######.### +##...#.##########... +#.##########.####### +.####.#.###.###.#.## +....##.##.###..##### +.#.#.###########.### +#.#.#.#####.####.### +###.##.####.##.#..##