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}