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(>->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(>->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 }