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}