puzzle.c (5426B)
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 <stdbool.h> 11 #include <math.h> 12 #include <unistd.h> 13 14 #include "util.h" 15 16 #define STR_LEN 1024 17 18 struct cmd_t { 19 enum ins_t {INP, ADD, MUL, DIV, MOD, EQL} instruction; 20 int reg1; 21 int reg2; 22 int op2; 23 }; 24 25 struct input_t { 26 int digits[14]; 27 int current; 28 }; 29 30 void parse_command(struct array_t *commands, char *str); 31 int get_register(char name); 32 int exec_cmd(struct cmd_t *cmd, int (*registers)[5], struct input_t *input); 33 34 int exec_inp(struct cmd_t *cmd, int (*registers)[5], struct input_t *input); 35 int exec_add(struct cmd_t *cmd, int (*registers)[5]); 36 int exec_mul(struct cmd_t *cmd, int (*registers)[5]); 37 int exec_div(struct cmd_t *cmd, int (*registers)[5]); 38 int exec_mod(struct cmd_t *cmd, int (*registers)[5]); 39 int exec_eql(struct cmd_t *cmd, int (*registers)[5]); 40 41 int read_input(struct input_t *input); 42 struct input_t make_input(uint64_t number); 43 bool valid_input(struct input_t *input); 44 bool validate_number(struct array_t *commands, uint64_t num); 45 46 void puzzle(const char *filename, long long *result1, long long *result2) { 47 FILE *infile = fopen(filename, "r"); 48 if (infile == NULL) { 49 fprintf(stderr, "fopen() error: %s\n", strerror(errno)); 50 return; 51 } 52 53 char buf[STR_LEN] = {0}; 54 struct array_t commands = { .data = NULL }; 55 array_init(&commands, sizeof(struct cmd_t), 10); 56 57 while (fgets(buf, STR_LEN, infile) != NULL) { 58 parse_command(&commands, buf); 59 bzero(buf, STR_LEN); 60 } 61 62 uint64_t max_num = 94992992796199; 63 uint64_t min_num = 11931881141161; 64 65 if (validate_number(&commands, max_num)) { 66 *result1 = max_num; 67 } 68 69 if (validate_number(&commands, min_num)) { 70 *result2 = min_num; 71 } 72 73 // mutiny! ignoring feof/ferror. 74 fclose(infile); 75 } 76 77 bool validate_number(struct array_t *commands, uint64_t num) { 78 struct input_t input = make_input(num); 79 if (valid_input(&input)) { 80 int registers[5] = {0}; 81 for (size_t k = 0; k < commands->count; ++k) { 82 struct cmd_t *cmd = &((struct cmd_t *)commands->data)[k]; 83 exec_cmd(cmd, ®isters, &input); 84 } 85 return registers[4] == 0; 86 } 87 return false; 88 } 89 90 void parse_command(struct array_t *commands, char *str) { 91 assert(commands != NULL); 92 assert(str != NULL); 93 int len = strlen(str); 94 assert(len >= 5); 95 if (commands->count >= commands->cap) array_expand(commands); 96 97 struct cmd_t *cmd = &((struct cmd_t *)commands->data)[commands->count++]; 98 if (strncmp(str, "inp", 3) == 0) { 99 cmd->instruction = INP; 100 } else if (strncmp(str, "add", 3) == 0) { 101 cmd->instruction = ADD; 102 } else if (strncmp(str, "mul", 3) == 0) { 103 cmd->instruction = MUL; 104 } else if (strncmp(str, "div", 3) == 0) { 105 cmd->instruction = DIV; 106 } else if (strncmp(str, "mod", 3) == 0) { 107 cmd->instruction = MOD; 108 } else if (strncmp(str, "eql", 3) == 0) { 109 cmd->instruction = EQL; 110 } else { 111 printf("invalid instruction %s", str); 112 exit(1); 113 } 114 115 cmd->reg1 = get_register(str[4]); 116 assert(cmd->reg1 != 0); 117 118 if (len < 7) { 119 return; 120 } 121 122 if (str[6] >= 'a' && str[6] <= 'z') { 123 cmd->reg2 = get_register(str[6]); 124 } else { 125 cmd->op2 = atoi(str+6); 126 } 127 } 128 129 int get_register(char name) { 130 switch (name) { 131 case 'w': return 1; 132 case 'x': return 2; 133 case 'y': return 3; 134 case 'z': return 4; 135 default: return 0; 136 } 137 } 138 139 int read_input(struct input_t *input) { 140 return input->digits[input->current++]; 141 } 142 143 struct input_t make_input(uint64_t num) { 144 struct input_t input = {0}; 145 for (int i = 0; i < 14; ++i) { 146 uint64_t mod = num % 10; 147 num /= 10; 148 input.digits[13-i] = mod; 149 } 150 return input; 151 } 152 153 bool valid_input(struct input_t *input) { 154 for (int i = 0; i < 14; ++i) { 155 if (input->digits[i] == 0) { 156 return false; 157 } 158 } 159 return true; 160 } 161 162 int exec_cmd(struct cmd_t *cmd, int (*registers)[5], struct input_t *input) { 163 assert(cmd != NULL); 164 assert(registers != NULL); 165 166 switch (cmd->instruction) { 167 case INP: return exec_inp(cmd, registers, input); 168 case ADD: return exec_add(cmd, registers); 169 case MUL: return exec_mul(cmd, registers); 170 case DIV: return exec_div(cmd, registers); 171 case MOD: return exec_mod(cmd, registers); 172 case EQL: return exec_eql(cmd, registers); 173 } 174 } 175 176 int exec_inp(struct cmd_t *cmd, int (*registers)[5], struct input_t *input) { 177 assert(cmd != NULL); 178 (*registers)[cmd->reg1] = read_input(input); 179 return (*registers)[cmd->reg1]; 180 } 181 182 int exec_add(struct cmd_t *cmd, int (*registers)[5]) { 183 assert(cmd != NULL); 184 int r = cmd->reg2 > 0 ? (*registers)[cmd->reg2] : cmd->op2; 185 (*registers)[cmd->reg1] += r; 186 return (*registers)[cmd->reg1]; 187 } 188 189 int exec_mul(struct cmd_t *cmd, int (*registers)[5]) { 190 assert(cmd != NULL); 191 int r = cmd->reg2 > 0 ? (*registers)[cmd->reg2] : cmd->op2; 192 (*registers)[cmd->reg1] *= r; 193 return (*registers)[cmd->reg1]; 194 } 195 196 int exec_div(struct cmd_t *cmd, int (*registers)[5]) { 197 assert(cmd != NULL); 198 int r = cmd->reg2 > 0 ? (*registers)[cmd->reg2] : cmd->op2; 199 (*registers)[cmd->reg1] /= r; 200 return (*registers)[cmd->reg1]; 201 } 202 203 int exec_mod(struct cmd_t *cmd, int (*registers)[5]) { 204 assert(cmd != NULL); 205 int r = cmd->reg2 > 0 ? (*registers)[cmd->reg2] : cmd->op2; 206 (*registers)[cmd->reg1] %= r; 207 return (*registers)[cmd->reg1]; 208 209 } 210 211 int exec_eql(struct cmd_t *cmd, int (*registers)[5]) { 212 assert(cmd != NULL); 213 int r = cmd->reg2 > 0 ? (*registers)[cmd->reg2] : cmd->op2; 214 (*registers)[cmd->reg1] = ((*registers)[cmd->reg1] == r) ? 1 : 0; 215 return (*registers)[cmd->reg1]; 216 }