common.c (10735B)
1 #include "common.h" 2 3 static inline size_t get_maxwidth(const char **lines, const size_t nlines) { 4 size_t i; 5 size_t max = 0; 6 for (i = 0; i < nlines - 2; i++) { 7 size_t ll = strlen(lines[i]) - 1; 8 if (max < ll) 9 max = ll; 10 } 11 return max; 12 } 13 14 board new_board(const size_t h, const size_t w) { 15 board b; 16 b.h = h; 17 b.w = w; 18 b.data = calloc(h * w, sizeof(*b.data)); 19 20 return b; 21 } 22 23 static inline void set_board(board *b, const char **lines, const size_t n) { 24 size_t i, j; 25 for (i = 0; i < n; i++) { 26 size_t ll = strlen(lines[i]) - 1; 27 for (j = 0; j < ll; j++) { 28 if (lines[i][j] == '.') { 29 b->data[i * b->w + j] = FRE; 30 } else if (lines[i][j] == '#') { 31 b->data[i * b->w + j] = STP; 32 } 33 } 34 } 35 } 36 37 static inline pos initial_pos(const board *b) { 38 pos r; 39 r.dir = EAST; 40 r.y = 0; 41 42 size_t i; 43 for (i = 0; i < b->w; i++) { 44 if (b->data[i] == FRE) { 45 r.x = i; 46 return r; 47 } 48 } 49 50 fprintf(stderr, "ERROR! No initial positon found\n"); 51 exit(1); 52 return r; 53 } 54 55 static inline void print_board(const board *b) { 56 size_t i, j; 57 for (i = 0; i < b->h; i++) { 58 for (j = 0; j < b->w; j++) { 59 switch (b->data[i * b->w + j]) { 60 case NON: 61 printf(" "); 62 break; 63 case STP: 64 printf("#"); 65 break; 66 case FRE: 67 printf("."); 68 break; 69 default: 70 printf("?"); 71 } 72 } 73 printf("\n"); 74 } 75 } 76 77 static inline void print_board_with_pos(const board *b, pos *p) { 78 size_t i, j; 79 for (i = 0; i < b->h; i++) { 80 for (j = 0; j < b->w; j++) { 81 if (p->x != j || p->y != i) { 82 switch (b->data[i * b->w + j]) { 83 case NON: 84 printf(" "); 85 break; 86 case STP: 87 printf("#"); 88 break; 89 case FRE: 90 printf("."); 91 break; 92 default: 93 printf("?"); 94 } 95 } else { 96 switch (p->dir) { 97 case NORTH: 98 printf("^"); 99 break; 100 case EAST: 101 printf(">"); 102 break; 103 case SOUTH: 104 printf("v"); 105 break; 106 case WEST: 107 printf("<"); 108 break; 109 default: 110 printf("?"); 111 } 112 } 113 } 114 printf("\n"); 115 } 116 } 117 118 move *get_moves(size_t *nmoves, const char *line) { 119 size_t ll = strlen(line); 120 move tmpm[ll]; 121 122 // x assumes that line starts and ends with numbers 123 124 size_t i = 0; 125 uint64_t tmp; 126 while ((line = sread_next_u64(&tmp, (char *)line)) != NULL) { 127 tmpm[i].n = tmp; 128 tmpm[i].turn = '\0'; 129 i++; 130 if (line != NULL && line[0] != '\n') { 131 tmpm[i].turn = line[0]; 132 tmpm[i].n = UINT64_MAX; 133 line++; 134 i++; 135 } 136 } 137 138 move *r = malloc(i * sizeof(*r)); 139 memcpy(r, tmpm, i * sizeof(*r)); 140 141 *nmoves = i; 142 143 return r; 144 } 145 146 void make_move(pos *p, const board *b, move m) { 147 if (m.n == UINT64_MAX) { 148 assert(m.turn == 'R' || m.turn == 'L'); 149 if (m.turn == 'R') { 150 p->dir = (p->dir + 1) % NDIR; 151 } else { 152 if (p->dir == 0) { 153 p->dir = NDIR - 1; 154 } else { 155 p->dir = p->dir - 1; 156 } 157 } 158 } else { 159 size_t oldx = SIZE_MAX, oldy = SIZE_MAX; 160 size_t steps = 0; 161 switch (p->dir) { 162 case NORTH: 163 do { 164 oldy = p->y; 165 if (p->y > 0 && b->data[(p->y - 1) * b->w + p->x] == FRE) { 166 p->y--; 167 } else if (p->y == 0 || b->data[(p->y - 1) * b->w + p->x] == NON) { 168 size_t y = b->h - 1; 169 while (b->data[y * b->w + p->x] == NON) { 170 y--; 171 } 172 if (b->data[y * b->w + p->x] == FRE) 173 p->y = y; 174 } 175 steps++; 176 } while (oldy != p->y && steps < m.n); 177 break; 178 case EAST: 179 do { 180 oldx = p->x; 181 if (p->x < b->w - 1 && b->data[p->y * b->w + p->x + 1] == FRE) { 182 p->x++; 183 } else if (p->x == b->w - 1 || b->data[p->y * b->w + p->x + 1] == NON) { 184 size_t x = 0; 185 while (b->data[p->y * b->w + x] == NON) { 186 x++; 187 } 188 if (b->data[p->y * b->w + x] == FRE) 189 p->x = x; 190 } 191 steps++; 192 } while (oldx != p->x && steps < m.n); 193 break; 194 case SOUTH: 195 do { 196 oldy = p->y; 197 if (p->y < b->h - 1 && b->data[(p->y + 1) * b->w + p->x] == FRE) { 198 p->y++; 199 } else if (p->y == b->h - 1 || 200 b->data[(p->y + 1) * b->w + p->x] == NON) { 201 size_t y = 0; 202 while (b->data[y * b->w + p->x] == NON) { 203 y++; 204 } 205 if (b->data[y * b->w + p->x] == FRE) 206 p->y = y; 207 } 208 steps++; 209 } while (oldy != p->y && steps < m.n); 210 break; 211 case WEST: 212 do { 213 oldx = p->x; 214 if (p->x > 0 && b->data[p->y * b->w + p->x - 1] == FRE) { 215 p->x--; 216 } else if (p->x == 0 || b->data[p->y * b->w + p->x - 1] == NON) { 217 size_t x = b->w - 1; 218 while (b->data[p->y * b->w + x] == NON) { 219 x--; 220 } 221 if (b->data[p->y * b->w + x] == FRE) 222 p->x = x; 223 } 224 steps++; 225 } while (oldx != p->x && steps < m.n); 226 break; 227 default: 228 fprintf(stderr, "ERROR! Unknown direction encountered\n"); 229 exit(1); 230 } 231 } 232 } 233 234 int64_t score_pos(pos *p) { 235 int64_t dirscore; 236 switch (p->dir) { 237 case EAST: 238 dirscore = 0; 239 break; 240 case SOUTH: 241 dirscore = 1; 242 break; 243 case WEST: 244 dirscore = 2; 245 break; 246 case NORTH: 247 dirscore = 3; 248 break; 249 default: 250 fprintf(stderr, "ERROR! Code 404\n"); 251 exit(1); 252 } 253 254 assert(dirscore < 4); 255 assert(dirscore >= 0); 256 257 int64_t row = (int64_t)p->y + 1; 258 int64_t col = (int64_t)p->x + 1; 259 260 return 1000 * row + 4 * col + dirscore; 261 } 262 263 size_t parse(board *b, pos *p, move **m, const char **lines, 264 const size_t nlines) { 265 size_t maxw = get_maxwidth(lines, nlines); 266 267 *b = new_board(nlines - 2, maxw); 268 set_board(b, lines, nlines - 2); 269 270 *p = initial_pos(b); 271 272 size_t nmoves; 273 *m = get_moves(&nmoves, lines[nlines - 1]); 274 275 return nmoves; 276 } 277 278 pos map_offboard(int64_t x, int64_t y, pos *p) { 279 pos r; 280 if (y == -1 && 50 <= x && x <= 99) { /* a,1 */ 281 r.x = (size_t)0; 282 r.y = (size_t)(x + 100); 283 assert(p->dir == NORTH); 284 r.dir = EAST; 285 } else if (x == -1 && 150 <= y && y <= 199) { /* a,2 */ 286 r.y = (size_t)0; 287 r.x = (size_t)(y - 100); 288 assert(p->dir == WEST); 289 r.dir = SOUTH; 290 } else if (x == 49 && 0 <= y && y <= 49) { /* b,1 */ 291 r.x = (size_t)0; 292 r.y = (size_t)(149 - y); 293 assert(p->dir == WEST); 294 r.dir = EAST; 295 } else if (x == -1 && 100 <= y && y <= 149) { /* b,2 */ 296 r.x = (size_t)50; 297 r.y = (size_t)(149 - y); 298 assert(p->dir == WEST); 299 r.dir = EAST; 300 } else if (x == 49 && 50 <= y && y <= 99) { /* c,1 */ 301 r.y = (size_t)100; 302 r.x = (size_t)(y - 50); 303 assert(p->dir == WEST); 304 r.dir = SOUTH; 305 } else if (y == 99 && 0 <= x && x <= 49) { /* c,2 */ 306 r.x = (size_t)50; 307 r.y = (size_t)(x + 50); 308 assert(p->dir == NORTH); 309 r.dir = EAST; 310 } else if (y == 150 && 50 <= x && x <= 99) { /* d,1 */ 311 r.x = (size_t)49; 312 r.y = (size_t)(x + 100); 313 assert(p->dir == SOUTH); 314 r.dir = WEST; 315 } else if (x == 50 && 150 <= y && y <= 199) { /* d,2 */ 316 r.y = (size_t)149; 317 r.x = (size_t)(y - 100); 318 assert(p->dir == EAST); 319 r.dir = NORTH; 320 } else if (x == 150 && 0 <= y && y <= 49) { /* e,1 */ 321 r.x = (size_t)99; 322 r.y = (size_t)(149 - y); 323 assert(p->dir == EAST); 324 r.dir = WEST; 325 } else if (x == 100 && 100 <= y && y <= 149) { /* e,2 */ 326 r.x = (size_t)149; 327 r.y = (size_t)(149 - y); 328 assert(p->dir == EAST); 329 r.dir = WEST; 330 } else if (y == 50 && 100 <= x && x <= 149) { /* f,1 */ 331 r.x = (size_t)99; 332 r.y = (size_t)(x - 50); 333 assert(p->dir == SOUTH); 334 r.dir = WEST; 335 } else if (x == 100 && 50 <= y && y <= 99) { /* f,2 */ 336 r.y = (size_t)49; 337 r.x = (size_t)(y + 50); 338 assert(p->dir == EAST); 339 r.dir = NORTH; 340 } else if (y == -1 && 100 <= x && x <= 149) { /* g,1 */ 341 r.y = (size_t)199; 342 r.x = (size_t)(x - 100); 343 assert(p->dir == NORTH); 344 r.dir = NORTH; 345 } else if (y == 200 && 0 <= x && x <= 49) { /* g,2 */ 346 r.y = (size_t)0; 347 r.x = (size_t)(x + 100); 348 assert(p->dir == SOUTH); 349 r.dir = SOUTH; 350 } else { 351 fprintf(stderr, "Bad position (%lld, %lld)\n", x, y); 352 exit(1); 353 } 354 355 return r; 356 } 357 358 void make_move_b(pos *p, const board *b, move m) { 359 if (m.n == UINT64_MAX) { 360 assert(m.turn == 'R' || m.turn == 'L'); 361 if (m.turn == 'R') { 362 p->dir = (p->dir + 1) % NDIR; 363 } else { 364 if (p->dir == 0) { 365 p->dir = NDIR - 1; 366 } else { 367 p->dir = p->dir - 1; 368 } 369 } 370 } else { 371 size_t oldx = SIZE_MAX, oldy = SIZE_MAX; 372 size_t steps = 0; 373 do { 374 oldy = p->y; 375 oldx = p->x; 376 switch (p->dir) { 377 case NORTH: 378 if (p->y > 0 && b->data[(p->y - 1) * b->w + p->x] == FRE) { 379 p->y--; 380 } else if (p->y == 0 || b->data[(p->y - 1) * b->w + p->x] == NON) { 381 int64_t wbx = (int64_t)p->x; 382 int64_t wby = ((int64_t)p->y) - 1; 383 pos tpos = map_offboard(wbx, wby, p); 384 if (b->data[tpos.y * b->w + tpos.x] == FRE) 385 *p = tpos; 386 } 387 steps++; 388 break; 389 case EAST: 390 if (p->x < b->w - 1 && b->data[p->y * b->w + p->x + 1] == FRE) { 391 p->x++; 392 } else if (p->x == b->w - 1 || b->data[p->y * b->w + p->x + 1] == NON) { 393 int64_t wbx = ((int64_t)p->x) + 1; 394 int64_t wby = (int64_t)p->y; 395 pos tpos = map_offboard(wbx, wby, p); 396 if (b->data[tpos.y * b->w + tpos.x] == FRE) 397 *p = tpos; 398 } 399 steps++; 400 break; 401 case SOUTH: 402 if (p->y < b->h - 1 && b->data[(p->y + 1) * b->w + p->x] == FRE) { 403 p->y++; 404 } else if (p->y == b->h - 1 || 405 b->data[(p->y + 1) * b->w + p->x] == NON) { 406 int64_t wbx = (int64_t)p->x; 407 int64_t wby = ((int64_t)p->y) + 1; 408 pos tpos = map_offboard(wbx, wby, p); 409 if (b->data[tpos.y * b->w + tpos.x] == FRE) 410 *p = tpos; 411 } 412 steps++; 413 break; 414 case WEST: 415 if (p->x > 0 && b->data[p->y * b->w + p->x - 1] == FRE) { 416 p->x--; 417 } else if (p->x == 0 || b->data[p->y * b->w + p->x - 1] == NON) { 418 int64_t wbx = ((int64_t)p->x) - 1; 419 int64_t wby = (int64_t)p->y; 420 pos tpos = map_offboard(wbx, wby, p); 421 if (b->data[tpos.y * b->w + tpos.x] == FRE) 422 *p = tpos; 423 } 424 steps++; 425 break; 426 default: 427 fprintf(stderr, "ERROR! Unknown direction encountered\n"); 428 exit(1); 429 } 430 } while ((oldy != p->y || oldx != p->x) && steps < m.n); 431 } 432 }