aocc22

Advent of Code 2022
git clone git://www.tkruger.se/aocc22.git
Log | Files | Refs | README

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 }