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