aocc23

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

uppgb.c (5036B)


      1 #include "common.h"
      2 
      3 #define ALPHSIZE 26
      4 #define BUTT 676
      5 #define BRDC 677
      6 
      7 #define QZ 441
      8 #define CQ 68
      9 #define JX 257
     10 #define TT 513
     11 
     12 typedef SIMPLEQ_HEAD(listhead, entry) head_t;
     13 
     14 typedef struct entry {
     15   size_t from;
     16   size_t to;
     17   uint8_t val;
     18 
     19   SIMPLEQ_ENTRY(entry) entries;
     20 } sig_t;
     21 
     22 typedef struct {
     23   char *name;
     24   uint8_t type;
     25 
     26   uint64_t state;
     27   size_t *inshift;
     28   size_t nstate;
     29 
     30   stack_u64 nbrs;
     31 } gate_t;
     32 
     33 static inline size_t pure_name_idx(char *s) {
     34   return ((s[0] - 'a') * ALPHSIZE + (s[1] - 'a'));
     35 }
     36 
     37 static inline size_t name_idx(char *s) {
     38   if (s[0] == 'b') {
     39     if (s[1] == 'r') {
     40       return BRDC;
     41     } else {
     42       return BUTT;
     43     }
     44   }
     45 
     46   return pure_name_idx(&s[1]);
     47 }
     48 
     49 static inline void init_gate(gate_t *gt, char *line) {
     50   gt->state = 0;
     51   gt->name = line;
     52 
     53   switch (line[0]) {
     54   case '&':
     55     gt->type = '&';
     56     break;
     57   case '%':
     58     gt->type = '%';
     59     break;
     60   default:
     61     gt->type = 'x';
     62   }
     63 
     64   stack_u64_init(&gt->nbrs);
     65 
     66   char *cp = line;
     67   while (*cp != ' ')
     68     cp++;
     69   cp++;
     70 
     71   while (*cp != '\n' && *cp != EOF) {
     72     while (*cp != ' ' && *cp != '\n' && *cp != EOF)
     73       cp++;
     74     if (*cp != ' ')
     75       break;
     76     cp++;
     77 
     78     stack_u64_push(&gt->nbrs, pure_name_idx(cp));
     79 
     80     cp++;
     81   }
     82 }
     83 
     84 static inline void init_states(gate_t *gates) {
     85   size_t i, j, to;
     86   size_t countin[BRDC + 1] = {0};
     87 
     88   for (i = 0; i < BRDC + 1; i++) {
     89     if (gates[i].name != NULL) {
     90       if (gates[i].type == '&') {
     91         gates[i].inshift = malloc((BRDC + 1) * sizeof(*(gates[i].inshift)));
     92       } else {
     93         gates[i].inshift = NULL;
     94       }
     95     }
     96   }
     97 
     98   for (i = 0; i < BRDC + 1; i++) {
     99     if (gates[i].name != NULL) {
    100       for (j = 0; j < gates[i].nbrs.nmemb; j++) {
    101         to = gates[i].nbrs.data[j];
    102         if (gates[to].type == '&')
    103           gates[to].inshift[i] = countin[to];
    104         countin[to]++;
    105       }
    106     }
    107   }
    108 
    109   for (i = 0; i < BRDC + 1; i++) {
    110     if (gates[i].name != NULL) {
    111       switch (gates[i].type) {
    112       case '%':
    113         gates[i].nstate = 1;
    114         break;
    115       case '&':
    116         gates[i].nstate = countin[i];
    117         break;
    118       default:
    119         gates[i].nstate = SIZE_MAX;
    120       }
    121     }
    122   }
    123 }
    124 
    125 static inline void send_pulses(gate_t *gate, size_t from, head_t *head,
    126                                uint8_t pulse) {
    127   size_t i;
    128   for (i = 0; i < gate->nbrs.nmemb; i++) {
    129     sig_t *n = malloc(sizeof(*n));
    130     n->from = from;
    131     n->to = gate->nbrs.data[i];
    132     n->val = pulse;
    133     SIMPLEQ_INSERT_TAIL(head, n, entries);
    134   }
    135 }
    136 
    137 static inline void set_bit(uint64_t *out, size_t i, uint8_t val) {
    138   assert(i < 63);
    139 
    140   if (val) {
    141     *out |= (1ULL << i);
    142   } else {
    143     *out &= (0xffffffffffffffffULL ^ (1ULL << i));
    144   }
    145 }
    146 
    147 static inline void push(gate_t *gates, size_t idx, size_t *cycla,
    148                         size_t *cyclb) {
    149   size_t i;
    150   head_t head = SIMPLEQ_HEAD_INITIALIZER(head);
    151 
    152   sig_t *s = malloc(sizeof(*s));
    153   s->from = BUTT;
    154   s->to = BRDC;
    155   s->val = 0;
    156 
    157   SIMPLEQ_INSERT_HEAD(&head, s, entries);
    158 
    159   uint64_t clow = 0;
    160   uint64_t chig = 0;
    161 
    162   while (!SIMPLEQ_EMPTY(&head)) {
    163     s = SIMPLEQ_FIRST(&head);
    164     SIMPLEQ_REMOVE_HEAD(&head, entries);
    165 
    166     if (s->val == 0) {
    167       clow++;
    168     } else {
    169       chig++;
    170     }
    171 
    172     if (s->val == 1 && s->to == 429) {
    173       if (cycla[s->from] == SIZE_MAX) {
    174         cycla[s->from] = idx + 1;
    175       } else if (cyclb[s->from] == SIZE_MAX && idx + 1 != cycla[s->from]) {
    176         cyclb[s->from] = idx + 1;
    177       }
    178     }
    179 
    180     switch (gates[s->to].type) {
    181     case '%':
    182       if (s->val == 0) {
    183         gates[s->to].state ^= 1;
    184         send_pulses(&gates[s->to], s->to, &head, (uint8_t)gates[s->to].state);
    185       }
    186       break;
    187     case '&':
    188       set_bit(&(gates[s->to].state), gates[s->to].inshift[s->from], s->val);
    189 
    190       uint8_t spulse = 0;
    191       for (i = 0; i < gates[s->to].nstate; i++) {
    192         if ((gates[s->to].state & (1ULL << i)) == 0) {
    193           spulse = 1;
    194           break;
    195         }
    196       }
    197 
    198       send_pulses(&gates[s->to], s->to, &head, spulse);
    199       break;
    200     case 'x':
    201       assert(s->from == BUTT);
    202       assert(s->to == BRDC);
    203       send_pulses(&gates[s->to], s->to, &head, 0);
    204       break;
    205     default:
    206       assert(s->to == 465); // rx the only one
    207     }
    208 
    209     free(s);
    210   }
    211 }
    212 
    213 int main(int argc, char **argv) {
    214   char **lines;
    215   size_t nlines = readlines(&lines, "input");
    216 
    217   gate_t gates[BRDC + 1];
    218   size_t i;
    219   for (i = 0; i < BRDC + 1; i++)
    220     gates[i].name = NULL;
    221 
    222   size_t g;
    223   for (i = 0; i < nlines; i++) {
    224     g = name_idx(lines[i]);
    225     init_gate(&gates[g], lines[i]);
    226   }
    227 
    228   init_states(gates);
    229 
    230   size_t cycla[BRDC + 1];
    231   size_t cyclb[BRDC + 1];
    232   for (i = 0; i < BRDC + 1; i++) {
    233     cycla[i] = SIZE_MAX;
    234     cyclb[i] = SIZE_MAX;
    235   }
    236 
    237   for (i = 0; i < 10000; i++) {
    238     push(gates, i, cycla, cyclb);
    239   }
    240 
    241   mpz_t p;
    242   mpz_init_set_ui(p, 1);
    243 
    244   for (i = 0; i < BRDC + 1; i++) {
    245     if (cycla[i] != SIZE_MAX) {
    246       assert(cyclb[i] == cycla[i] * 2); // this makes the cycle possible
    247       mpz_lcm_ui(p, p, cycla[i]);
    248     }
    249   }
    250 
    251   gmp_printf("%Zd\n", p);
    252 
    253   mpz_clear(p);
    254 }