part1.c (6140B)
1#include "allocator.h" 2#include "aoc.h" 3#include "hmap.h" 4#include "hmap_s.h" 5#include "vec_s.h" 6#include "util.h" 7#include "list.h" 8 9#include <assert.h> 10#include <ctype.h> 11#include <stdbool.h> 12#include <stdint.h> 13#include <stdlib.h> 14 15#define PORTAL_ID(a, b) ((size_t) ((uint8_t) (a) * 100 + (uint8_t) (b))) 16 17struct djk_state { 18 size_t dist; 19 struct vec2i pos; 20 21 struct list_link link; 22}; 23 24static bool 25djk_dist_ordering(const void *p1, const void *p2, void *u) 26{ 27 const struct djk_state *s1 = p1, *s2 = p2; 28 29 return s1->dist < s2->dist; 30} 31 32static void 33load_map(struct hmap *map, const char *input, size_t len) 34{ 35 char line[256]; 36 const char *lpos, *lend; 37 struct vec2i pos, *key; 38 39 lpos = aoc.input; 40 lend = lpos + aoc.input_size; 41 vec2i_setv(&pos, 0, 0); 42 while (readtok(line, sizeof(line), '\n', &lpos, lend)) { 43 for (pos.x = 0; line[pos.x]; pos.x++) { 44 if (line[pos.x] == ' ') 45 continue; 46 key = malloc(sizeof(struct vec2i)); 47 vec2i_set(key, &pos); 48 hmap_add(map, (struct hmap_key) {.p = key}, 49 (struct hmap_val) {.c = line[pos.x]}); 50 } 51 pos.y += 1; 52 } 53} 54 55static void 56load_portals(struct hmap *portals, struct hmap *map) 57{ 58 struct hmap_link *link1; 59 struct hmap_link *link2; 60 struct hmap_iter iter; 61 struct vec2i pos; 62 struct vec2i npos; 63 struct vec2i *key; 64 size_t i, id; 65 66 for (HMAP_ITER(map, iter)) { 67 if (!isupper(iter.link->value.c)) 68 continue; 69 70 vec2i_set(&pos, iter.link->key.p); 71 for (i = 0; i < 4; i++) { 72 vec2i_add(&npos, &pos, &adj[i]); 73 link1 = hmap_get(map, (struct hmap_key) {.p = &npos}); 74 if (link1 && isupper(link1->value.c)) 75 break; 76 } 77 if (i != ADJ_SOUTH && i != ADJ_EAST) 78 continue; 79 80 for (i = 0; i < 4; i++) { 81 vec2i_add(&npos, &pos, &adj[i]); 82 link2 = hmap_get(map, (struct hmap_key) {.p = &npos}); 83 if (link2 && link2->value.c == '.') 84 break; 85 } 86 if (i == 4) { 87 for (i = 0; i < 4; i++) { 88 vec2i_add(&npos, link1->key.p, &adj[i]); 89 link2 = hmap_get(map, (struct hmap_key) {.p = &npos}); 90 if (link2 && link2->value.c == '.') 91 break; 92 } 93 } 94 assert(i != 4); 95 96 aoc_debug("FOUND %c %c\n", iter.link->value.c, link1->value.c); 97 98 key = memdup(link2->key.p, sizeof(struct vec2i)); 99 id = PORTAL_ID(iter.link->value.c, link1->value.c); 100 hmap_add(portals, (struct hmap_key) {.p = key}, 101 (struct hmap_val) {.s = id}); 102 } 103} 104 105static bool 106get_portal(struct hmap *portals, struct vec2i *pos, struct vec2i *skip, size_t id) 107{ 108 struct hmap_iter iter; 109 110 for (HMAP_ITER(portals, iter)) { 111 if (skip && vec2i_eql(skip, iter.link->key.p)) 112 continue; 113 if (iter.link->value.s == id) { 114 vec2i_set(pos, iter.link->key.p); 115 return true; 116 } 117 } 118 119 return false; 120} 121 122static void 123add_djk_state(struct list *active, struct hmap *distmap, 124 struct hmap *portals, struct vec2i *pos, size_t dist) 125{ 126 struct hmap_link **hmap_linkp; 127 struct djk_state *nstate; 128 struct vec2i *key; 129 bool new; 130 131 hmap_linkp = hmap_link_pos(distmap, (struct hmap_key) {.p = pos}); 132 if (!*hmap_linkp) { 133 key = memdup(pos, sizeof(struct vec2i)); 134 *hmap_linkp = hmap_link_alloc(distmap, 135 (struct hmap_key) {.p = key}, 136 (struct hmap_val) {.s = dist}, NULL); 137 new = true; 138 } else { 139 if (dist < (*hmap_linkp)->value.s) { 140 (*hmap_linkp)->value.s = dist; 141 new = true; 142 } else { 143 new = false; 144 } 145 } 146 147 if (new) { 148 nstate = malloc(sizeof(struct djk_state)); 149 nstate->dist = dist; 150 vec2i_set(&nstate->pos, pos); 151 nstate->link = LIST_LINK_INIT; 152 list_insert_sorted(active, &nstate->link, 153 false, djk_dist_ordering, 154 LIST_OFFSET(struct djk_state, link), NULL); 155 } 156} 157 158static size_t 159min_dist(struct hmap *map, struct hmap *portals, 160 struct vec2i *start, struct vec2i *end) 161{ 162 struct list active; 163 struct hmap distmap; 164 struct list_link *list_link; 165 struct hmap_link *hmap_link; 166 struct hmap_iter hmap_iter; 167 struct djk_state *state; 168 struct vec2i *key, npos; 169 size_t mdist, i; 170 171 list_init(&active); 172 hmap_init(&distmap, 256, vec2i_hmap_hash, vec2i_hmap_keycmp, 173 &stdlib_strict_heap_allocator); 174 175 state = malloc(sizeof(struct djk_state)); 176 state->dist = 0; 177 vec2i_set(&state->pos, start); 178 list_insert_front(&active, &state->link); 179 180 key = memdup(start, sizeof(struct vec2i)); 181 hmap_add(&distmap, (struct hmap_key) {.p = key}, 182 (struct hmap_val) {.s = 0}); 183 184 mdist = 0; 185 while (!list_empty(&active)) { 186 list_link = list_front(&active); 187 state = LIST_UPCAST(list_link, struct djk_state, link); 188 if (vec2i_eql(&state->pos, end)) { 189 mdist = state->dist; 190 goto exit; 191 } 192 193 list_link_pop(list_link); 194 195 hmap_link = hmap_get(&distmap, (struct hmap_key) {.p = &state->pos}); 196 assert(hmap_link); 197 if (state->dist != hmap_link->value.s) { 198 free(state); 199 continue; 200 } 201 202 hmap_link = hmap_get(portals, (struct hmap_key) {.p = &state->pos}); 203 if (hmap_link) { 204 if (get_portal(portals, &npos, &state->pos, hmap_link->value.s)) 205 add_djk_state(&active, &distmap, portals, 206 &npos, state->dist + 1); 207 } 208 209 for (i = 0; i < 4; i++) { 210 vec2i_add(&npos, &state->pos, &adj[i]); 211 hmap_link = hmap_get(map, (struct hmap_key) {.p = &npos}); 212 if (!hmap_link || hmap_link->value.c != '.') continue; 213 add_djk_state(&active, &distmap, portals, 214 &npos, state->dist + 1); 215 } 216 217 free(state); 218 } 219 220exit: 221 for (HMAP_ITER(&distmap, hmap_iter)) 222 free(hmap_iter.link->key._p); 223 hmap_deinit(&distmap); 224 list_free_items(&active, free, LIST_OFFSET(struct djk_state, link)); 225 226 return mdist; 227} 228 229void 230part1(void) 231{ 232 struct hmap map; 233 struct hmap portals; 234 struct hmap_iter iter; 235 struct vec2i start, end; 236 size_t answer; 237 238 hmap_init(&map, 256, vec2i_hmap_hash, vec2i_hmap_keycmp, 239 &stdlib_strict_heap_allocator); 240 hmap_init(&portals, 256, vec2i_hmap_hash, vec2i_hmap_keycmp, 241 &stdlib_strict_heap_allocator); 242 243 load_map(&map, aoc.input, aoc.input_size); 244 load_portals(&portals, &map); 245 246 assert(get_portal(&portals, &start, NULL, PORTAL_ID('A', 'A'))); 247 assert(get_portal(&portals, &end, NULL, PORTAL_ID('Z', 'Z'))); 248 answer = min_dist(&map, &portals, &start, &end); 249 250 aoc.answer = aprintf("%lu", answer); 251 aoc.solution = "656"; 252 253 for (HMAP_ITER(&portals, iter)) 254 free(iter.link->key._p); 255 hmap_deinit(&portals); 256 for (HMAP_ITER(&map, iter)) 257 free(iter.link->key._p); 258 hmap_deinit(&map); 259}