aocc23

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

uppga.c (4462B)


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