uppgb.c (6820B)
1 #include "common.h" 2 3 typedef struct { 4 size_t na; 5 size_t nb; 6 } pos_t; 7 8 static inline pos_t compute_nbrs(size_t row, size_t col, char **lines, 9 size_t nrows, size_t ncols) { 10 pos_t r; 11 12 switch (lines[row][col]) { 13 case '|': 14 if (row == 0 || row == nrows - 1) { 15 r.na = SIZE_MAX; 16 r.nb = SIZE_MAX; 17 } else { 18 r.na = (row - 1) * ncols + col; 19 r.nb = (row + 1) * ncols + col; 20 } 21 break; 22 case '-': 23 if (col == 0 || col == ncols - 1) { 24 r.na = SIZE_MAX; 25 r.nb = SIZE_MAX; 26 } else { 27 r.na = row * ncols + col - 1; 28 r.nb = row * ncols + col + 1; 29 } 30 break; 31 case 'F': 32 if (col == ncols - 1 || row == nrows - 1) { 33 r.na = SIZE_MAX; 34 r.nb = SIZE_MAX; 35 } else { 36 r.na = row * ncols + col + 1; 37 r.nb = (row + 1) * ncols + col; 38 } 39 break; 40 case '7': 41 if (col == 0 || row == nrows - 1) { 42 r.na = SIZE_MAX; 43 r.nb = SIZE_MAX; 44 } else { 45 r.na = row * ncols + col - 1; 46 r.nb = (row + 1) * ncols + col; 47 } 48 break; 49 case 'L': 50 if (col == ncols - 1 || row == 0) { 51 r.na = SIZE_MAX; 52 r.nb = SIZE_MAX; 53 } else { 54 r.na = (row - 1) * ncols + col; 55 r.nb = row * ncols + col + 1; 56 } 57 break; 58 case 'J': 59 if (col == 0 || row == 0) { 60 r.na = SIZE_MAX; 61 r.nb = SIZE_MAX; 62 } else { 63 r.na = (row - 1) * ncols + col; 64 r.nb = row * ncols + col - 1; 65 } 66 break; 67 default: // S or . 68 r.na = SIZE_MAX; 69 r.nb = SIZE_MAX; 70 } 71 72 return r; 73 } 74 75 static inline size_t traverse(char *type, size_t start, size_t next, pos_t *ns, 76 uint8_t *visited, size_t nn) { 77 size_t head = next; 78 size_t tail = start; 79 size_t steps = 0; 80 81 int exit = 0; 82 if (head > tail) { 83 if (head - tail == 1) { 84 exit = 1; // east 85 } else { 86 exit = 2; // south 87 } 88 } else { 89 if (tail - head == 1) { 90 exit = 3; // west 91 } else { 92 exit = 4; // north 93 } 94 } 95 96 memset(visited, nn, sizeof(*visited)); 97 visited[head] = 1; 98 visited[tail] = 1; 99 100 if (ns[head].na != tail && ns[head].nb != tail) { 101 return SIZE_MAX; 102 } 103 104 while (head != start && ns[head].na != SIZE_MAX) { 105 size_t tmp = head; 106 if (ns[head].na == tail) { 107 head = ns[head].nb; 108 } else { 109 head = ns[head].na; 110 } 111 tail = tmp; 112 visited[head] = 1; 113 steps++; 114 } 115 116 int enter = 0; 117 if (head > tail) { 118 if (head - tail == 1) { 119 enter = 3; // east 120 } else { 121 enter = 4; // south 122 } 123 } else { 124 if (tail - head == 1) { 125 enter = 1; // west 126 } else { 127 enter = 2; // north 128 } 129 } 130 131 if (exit == 1) { 132 if (enter == 2) { 133 *type = 'F'; 134 } else if (enter == 3) { 135 *type = '-'; 136 } else if (enter == 4) { 137 *type = 'L'; 138 } 139 } else if (exit == 2) { 140 if (enter == 1) { 141 *type = 'F'; 142 } else if (enter == 3) { 143 *type = '7'; 144 } else if (enter == 4) { 145 *type = '|'; 146 } 147 } else if (exit == 3) { 148 if (enter == 1) { 149 *type = '-'; 150 } else if (enter == 2) { 151 *type = '7'; 152 } else if (enter == 4) { 153 *type = 'J'; 154 } 155 } else if (exit == 4) { 156 if (enter == 1) { 157 *type = 'L'; 158 } else if (enter == 2) { 159 *type = '|'; 160 } else if (enter == 3) { 161 *type = 'J'; 162 } 163 } 164 165 if (head == start) 166 return steps; 167 168 return SIZE_MAX; 169 } 170 171 #define IDX(r, c, n) ((3 * n) * (3 * r + 1) + (3 * c) + 1) 172 173 int main(int argc, char **argv) { 174 char **lines; 175 size_t i, j; 176 size_t nlines = readlines(&lines, "input"); 177 178 size_t ncols = strlen(lines[0]) - 1; 179 180 size_t start; 181 pos_t ns[nlines * ncols]; 182 for (i = 0; i < nlines; i++) { 183 for (j = 0; j < ncols; j++) { 184 ns[i * ncols + j] = compute_nbrs(i, j, lines, nlines, ncols); 185 if (lines[i][j] == 'S') { 186 start = i * ncols + j; 187 } 188 } 189 } 190 191 uint8_t visited[nlines * ncols]; 192 size_t r; 193 char type; 194 if ((r = traverse(&type, start, start + 1, ns, visited, nlines * ncols)) != 195 SIZE_MAX) { 196 } else if ((r = traverse(&type, start, start - 1, ns, visited, 197 nlines * ncols)) != SIZE_MAX) { 198 } else if ((r = traverse(&type, start, start + ncols, ns, visited, 199 nlines * ncols)) != SIZE_MAX) { 200 } else { 201 printf("bad\n"); 202 exit(1); 203 } 204 visited[0] = 0; 205 206 for (i = 0; i < nlines; i++) { 207 for (j = 0; j < ncols; j++) { 208 if (!visited[i * ncols + j]) { 209 lines[i][j] = '.'; 210 } 211 if (lines[i][j] == 'S') 212 lines[i][j] = type; 213 } 214 } 215 216 uint8_t *expander = calloc((3 * ncols * 3 * nlines), sizeof(*expander)); 217 218 for (i = 0; i < nlines; i++) { 219 for (j = 0; j < ncols; j++) { 220 switch (lines[i][j]) { 221 case '-': 222 expander[IDX(i, j, ncols)] = 1; 223 expander[IDX(i, j, ncols) - 1] = 1; 224 expander[IDX(i, j, ncols) + 1] = 1; 225 break; 226 case '|': 227 expander[IDX(i, j, ncols)] = 1; 228 expander[IDX(i, j, ncols) - 3 * ncols] = 1; 229 expander[IDX(i, j, ncols) + 3 * ncols] = 1; 230 break; 231 case 'F': 232 expander[IDX(i, j, ncols)] = 1; 233 expander[IDX(i, j, ncols) + 1] = 1; 234 expander[IDX(i, j, ncols) + 3 * ncols] = 1; 235 break; 236 case '7': 237 expander[IDX(i, j, ncols)] = 1; 238 expander[IDX(i, j, ncols) - 1] = 1; 239 expander[IDX(i, j, ncols) + 3 * ncols] = 1; 240 break; 241 case 'L': 242 expander[IDX(i, j, ncols)] = 1; 243 expander[IDX(i, j, ncols) + 1] = 1; 244 expander[IDX(i, j, ncols) - 3 * ncols] = 1; 245 break; 246 case 'J': 247 expander[IDX(i, j, ncols)] = 1; 248 expander[IDX(i, j, ncols) - 1] = 1; 249 expander[IDX(i, j, ncols) - 3 * ncols] = 1; 250 break; 251 default: 252 expander[IDX(i, j, ncols)] = 0; 253 break; 254 } 255 } 256 } 257 258 stack_u64 stack; 259 stack_u64_init(&stack); 260 stack_u64_push(&stack, 0); 261 expander[0] = 1; 262 263 size_t x; 264 while (stack.nmemb > 0) { 265 x = stack_u64_pop(&stack); 266 267 if (x % (3 * ncols) != 0 && expander[x - 1] == 0) { 268 stack_u64_push(&stack, x - 1); 269 expander[x - 1] = 1; 270 } 271 272 if ((x + 1) % (3 * ncols) != 0 && expander[x + 1] == 0) { 273 stack_u64_push(&stack, x + 1); 274 expander[x + 1] = 1; 275 } 276 277 if ((x >= 3 * ncols) && expander[x - 3 * ncols] == 0) { 278 stack_u64_push(&stack, x - 3 * ncols); 279 expander[x - 3 * ncols] = 1; 280 } 281 282 if ((x < (3 * nlines - 1) * (3 * ncols)) && expander[x + 3 * ncols] == 0) { 283 stack_u64_push(&stack, x + 3 * ncols); 284 expander[x + 3 * ncols] = 1; 285 } 286 } 287 288 uint64_t count = 0; 289 for (i = 0; i < 3 * nlines; i++) { 290 for (j = 0; j < 3 * ncols; j++) { 291 if (!expander[(3 * ncols) * i + j]) { 292 if (i % 3 == 1 && j % 3 == 1) { 293 count++; 294 } 295 } 296 } 297 } 298 299 printf("%llu\n", count); 300 301 free(expander); 302 }