advent2021

Advent of Code 2021 Solutions
git clone git://bsandro.tech/advent2021
Log | Files | Refs | README | LICENSE

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, &registers, &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 }