puzzle.c (7631B)
1 #define _DEFAULT_SOURCE 2 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <errno.h> 6 #include <string.h> 7 #include <strings.h> 8 #include <assert.h> 9 #include <ctype.h> 10 #include <limits.h> 11 #include <stdbool.h> 12 13 #include "util.h" 14 15 #define STR_LEN 32 16 17 struct rule_t { 18 char name[3]; 19 char child; 20 struct rule_t *children[2]; 21 long long score; 22 }; 23 24 struct count_t { 25 struct rule_t *section; 26 char symbol; 27 unsigned long long count; 28 }; 29 30 long long parse_rule(struct array_t *rules, const char *str); 31 void process_rules(struct array_t *rules); 32 struct rule_t * get_rule(struct array_t *rules, const char name[3]); 33 struct array_t make_sections_count(struct array_t *sections); 34 void add_section_count(struct array_t *counts, struct rule_t *section, unsigned long long count); 35 void add_symbol_count(struct array_t *counts, char symbol, unsigned long long multiplier); 36 unsigned long long get_min_count(const struct array_t *counts); 37 unsigned long long get_max_count(const struct array_t *counts); 38 struct array_t make_sections(struct array_t *orig_rules, const char *str); 39 struct array_t iterate_sections_count(struct array_t *rules, struct array_t counts); 40 unsigned long long get_char_counts(struct array_t counts); 41 42 void puzzle(const char *filename, unsigned long long *result1, unsigned long long *result2) { 43 FILE *infile = fopen(filename, "r"); 44 if (infile == NULL) { 45 fprintf(stderr, "fopen() error: %s\n", strerror(errno)); 46 return; 47 } 48 49 char buf[STR_LEN] = {0}; 50 unsigned int line_num = 0; 51 52 bool rules_started = false; 53 char *str = NULL; 54 struct array_t rules = { .data = NULL }; 55 array_init(&rules, sizeof(struct rule_t), 10); 56 while (fgets(buf, STR_LEN, infile) != NULL) { 57 if (strlen(buf) == 1) { 58 rules_started = true; 59 continue; 60 } 61 if (rules_started) { 62 parse_rule(&rules, buf); 63 } else { 64 assert(str == NULL); 65 size_t len = strlen(buf); 66 str = malloc(len); 67 bzero(str, len); 68 strncpy(str, buf, len-1); // losing last symbol \n 69 } 70 ++line_num; 71 bzero(buf, STR_LEN); 72 } 73 74 process_rules(&rules); 75 struct array_t sections = make_sections(&rules, str); 76 struct array_t sections_count = make_sections_count(§ions); 77 78 for (int i = 0; i < 40; ++i) { 79 struct array_t sections_count1 = iterate_sections_count(&rules, sections_count); 80 free(sections_count.data); 81 sections_count = sections_count1; 82 83 if (i == 9) { 84 *result1 = get_char_counts(sections_count); 85 } 86 } 87 88 *result2 = get_char_counts(sections_count); 89 90 free(str); 91 free(sections.data); 92 free(sections_count.data); 93 free(rules.data); 94 // mutiny! ignoring feof/ferror. 95 fclose(infile); 96 } 97 98 struct array_t iterate_sections_count(struct array_t *rules, struct array_t counts) { 99 assert(rules != NULL); 100 struct array_t new_counts = { .data = NULL }; 101 array_init(&new_counts, sizeof(struct count_t), counts.cap); 102 103 struct count_t *counts_data = counts.data; 104 for (size_t i = 0; i < counts.count; ++i) { 105 struct rule_t *rule = counts_data[i].section; 106 if (counts_data[i].count > 0) { 107 add_section_count(&new_counts, rule->children[0], counts_data[i].count); 108 add_section_count(&new_counts, rule->children[1], counts_data[i].count); 109 } 110 } 111 112 return new_counts; 113 } 114 115 struct array_t make_sections_count(struct array_t *sections) { 116 struct array_t counts = { .data = NULL }; 117 array_init(&counts, sizeof(struct count_t), 10); 118 struct rule_t **data = sections->data; 119 for (size_t i = 0; i < sections->count; ++i) { 120 add_section_count(&counts, data[i], 1); 121 } 122 123 return counts; 124 } 125 126 unsigned long long get_char_counts(struct array_t counts) { 127 struct array_t char_counts = { .data = NULL }; 128 array_init(&char_counts, sizeof(struct count_t), 10); 129 130 struct count_t *counts_data = counts.data; 131 for (size_t i = 0; i < counts.count; ++i) { 132 if (i == 0) { 133 add_symbol_count(&char_counts, counts_data[i].section->name[0], 1); 134 } 135 add_symbol_count(&char_counts, counts_data[i].section->name[1], counts_data[i].count); 136 } 137 138 unsigned long long count_min = get_min_count(&char_counts); 139 unsigned long long count_max = get_max_count(&char_counts); 140 141 return count_max - count_min; 142 } 143 144 void add_section_count(struct array_t *counts, struct rule_t *section, unsigned long long count) { 145 assert(counts != NULL); 146 assert(section != NULL); 147 struct count_t *data = counts->data; 148 for (size_t i = 0; i < counts->count; ++i) { 149 if (data[i].section == section) { 150 data[i].count += count; 151 return; 152 } 153 } 154 155 if (counts->count >= counts->cap) { 156 array_expand(counts); 157 } 158 data = counts->data; 159 data[counts->count++] = (struct count_t){ .section = section, .count = count }; 160 } 161 162 void add_symbol_count(struct array_t *counts, char symbol, unsigned long long multiplier) { 163 assert(counts != NULL); 164 struct count_t *data = counts->data; 165 for (size_t i = 0; i < counts->count; ++i) { 166 if (data[i].symbol == symbol) { 167 data[i].count += multiplier; 168 return; 169 } 170 } 171 172 if (counts->count >= counts->cap) { 173 array_expand(counts); 174 } 175 data = counts->data; 176 data[counts->count++] = (struct count_t){ .symbol = symbol, .count = multiplier }; 177 } 178 179 180 unsigned long long get_max_count(const struct array_t *counts) { 181 assert(counts != NULL); 182 struct count_t *data = counts->data; 183 unsigned long long max = 0; 184 for (size_t i = 0; i < counts->count; ++i) { 185 max = data[i].count > max ? data[i].count : max; 186 } 187 return max; 188 } 189 190 unsigned long long get_min_count(const struct array_t *counts) { 191 assert(counts != NULL); 192 struct count_t *data = counts->data; 193 unsigned long long min = ULLONG_MAX; 194 for (size_t i = 0; i < counts->count; ++i) { 195 min = data[i].count < min ? data[i].count : min; 196 } 197 return min; 198 } 199 200 long long parse_rule(struct array_t *rules, const char *str) { 201 assert(rules != NULL); 202 assert(str != NULL); 203 char *tmp = strndup(str, STR_LEN); 204 assert(tmp != NULL); 205 char *token = NULL; 206 207 int n = 0; 208 struct rule_t rule = {0}; 209 while ((token = strsep(&tmp, " ->\n")) != NULL) { 210 if (*token != '\0') { 211 assert(n < 2); 212 if (n == 0) { 213 assert(strlen(token) == 2); 214 strncpy(rule.name, token, 3); 215 rule.score = rule.name[0] * 1000 + rule.name[1]; 216 } else { 217 assert(strlen(token) == 1); 218 rule.child = token[0]; 219 } 220 n++; 221 } 222 } 223 224 if (rules->count >= rules->cap) { 225 array_expand(rules); 226 } 227 228 struct rule_t *data = rules->data; 229 data[rules->count++] = rule; 230 free(tmp); 231 return rule.score; 232 } 233 234 void process_rules(struct array_t *rules) { 235 assert(rules != NULL); 236 struct rule_t *data = rules->data; 237 for (size_t i = 0; i < rules->count; ++i) { 238 char name1[3] = {0}; 239 char name2[3] = {0}; 240 name1[0] = data[i].name[0]; 241 name1[1] = data[i].child; 242 name2[0] = data[i].child; 243 name2[1] = data[i].name[1]; 244 struct rule_t *child1 = get_rule(rules, name1); 245 struct rule_t *child2 = get_rule(rules, name2); 246 assert(child1 != NULL); 247 assert(child2 != NULL); 248 data[i].children[0] = child1; 249 data[i].children[1] = child2; 250 } 251 } 252 253 struct rule_t * get_rule(struct array_t *rules, const char name[3]) { 254 assert(rules != NULL); 255 struct rule_t *data = rules->data; 256 for (size_t i = 0; i < rules->count; ++i) { 257 if (data[i].name[0] == name[0] && data[i].name[1] == name[1]) { 258 return &data[i]; 259 } 260 } 261 return NULL; 262 } 263 264 struct array_t make_sections(struct array_t *rules, const char *str) { 265 assert(str != NULL); 266 assert(rules != NULL); 267 size_t len = strlen(str); 268 struct array_t sections = { .data = NULL }; 269 array_init(§ions, sizeof(void *), 10); 270 for (size_t i = 0; i < len - 1; ++i) { 271 char name[3] = { str[i], str[i+1], 0}; 272 if (sections.count >= sections.cap) { 273 array_expand(§ions); 274 } 275 struct rule_t **data = sections.data; 276 struct rule_t *rule = get_rule(rules, name); 277 assert(rule != NULL); 278 data[sections.count++] = rule; 279 } 280 281 return sections; 282 }