aoc/2015/day07/answer02.c

176 lines
4.4 KiB
C
Raw Permalink Normal View History

2024-07-05 19:55:39 -04:00
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
typedef enum {
ASSIGN,
AND,
OR,
LSHIFT,
RSHIFT,
NOT
} Gate;
typedef struct {
char l_operand[3];
char r_operand[3];
Gate gate;
bool assigned;
uint16_t value;
} Wire;
/* hash: for single character strings, convert the character to its natural index.
* for two character strings, treat the string as a base 26 number.
* e.g., a -> 0, b -> 1, ..., z -> 25, aa -> 26, ..., etc.
*/
int32_t hash(char *str) {
int32_t length = strlen(str);
if (length == 1) {
return str[0] - 'a';
} else if (length == 2) {
return 26 * ((str[0] - 'a') + 1) + (str[1] - 'a');
} else {
return -1;
}
}
// is_int: return 1 if the string argument is an integer; 0 otherwise.
int32_t is_int(char *str) {
while (isspace((unsigned char)*str)) str++;
if (*str == '\0') return 0;
char *endptr;
errno = 0;
int64_t val = strtol(str, &endptr, 10);
if (endptr == str || ((val == LONG_MIN || val == LONG_MAX) && errno == ERANGE)) {
return 0;
}
while (isspace((unsigned char)*endptr)) endptr++;
if (*endptr != '\0') return 0;
return 1;
}
// get_value: recursively determine the value of the Wire given its name.
int32_t get_value(Wire *wire, char *wire_name) {
if (is_int(wire_name)) {
return atoi(wire_name);
}
uint32_t index = hash(wire_name);
if (wire[index].assigned == true) {
return wire[index].value;
}
uint16_t l_operand, r_operand;
if (wire[index].l_operand[0] != '\0')
l_operand = get_value(wire, wire[index].l_operand);
if (wire[index].r_operand[0] != '\0')
r_operand = get_value(wire, wire[index].r_operand);
switch(wire[index].gate) {
case ASSIGN:
wire[index].assigned = true;
return wire[index].value = r_operand;
break;
case AND:
wire[index].assigned = true;
return wire[index].value = l_operand & r_operand;
break;
case OR:
wire[index].assigned = true;
return wire[index].value = l_operand | r_operand;
break;
case LSHIFT:
wire[index].assigned = true;
return wire[index].value = l_operand << r_operand;
break;
case RSHIFT:
wire[index].assigned = true;
return wire[index].value = l_operand >> r_operand;
break;
case NOT:
wire[index].assigned = true;
return wire[index].value = ~r_operand;
break;
}
//bad gate
perror("get_value: bad gate.");
return -1;
}
// process: insert each wire definition (i.e., instruction) into the Wire array.
void process(Wire *wire, char *left, char *right) {
uint32_t index = hash(right);
if (strstr(left, "AND") != NULL) {
sscanf(left, "%s AND %s", wire[index].l_operand, wire[index].r_operand);
wire[index].gate = AND;
} else if (strstr(left, "OR") != NULL) {
sscanf(left, "%s OR %s", wire[index].l_operand, wire[index].r_operand);
wire[index].gate = OR;
} else if(strstr(left, "LSHIFT") != NULL) {
sscanf(left, "%s LSHIFT %s", wire[index].l_operand, wire[index].r_operand);
wire[index].gate = LSHIFT;
} else if (strstr(left, "RSHIFT") != NULL) {
sscanf(left, "%s RSHIFT %s", wire[index].l_operand, wire[index].r_operand);
wire[index].gate = RSHIFT;
} else if (strstr(left, "NOT") != NULL) {
sscanf(left, "NOT %s", wire[index].r_operand);
wire[index].gate = NOT;
} else if (!is_int(left)) { //test for definitions like "x -> y"
strcpy(wire[index].r_operand, left);
uint64_t len = strlen(wire[index].r_operand);
//remove trailing whitespace
for (uint64_t i = len - 1; i >= 0; i--) {
if (isspace((unsigned char)wire[index].r_operand[i])) {
wire[index].r_operand[i] = '\0';
} else {
break;
}
}
wire[index].gate = ASSIGN;
} else { //if we end up here, the definition must be like "123 -> x"
wire[index].value = atoi(left);
wire[index].assigned = true;
}
}
int main() {
FILE *file = fopen("input2", "r");
if (file == NULL) {
perror("main: error opening file.");
return 1;
}
uint16_t index = 26*26;
Wire wire[index];
char left[20]; //20 is suffcient to hold the longest possible definition.
char right[3]; //3 is sufficient for any one or two character wire name.
for (uint16_t i = 0; i < index; i++) {
wire[i].l_operand[0] = '\0';
wire[i].r_operand[0] = '\0';
wire[i].gate = ASSIGN;
wire[i].assigned = false;
wire[i].value = 0;
}
while (fscanf(file, "%20[a-zA-Z0-9 ] -> %s\n", left, right) != EOF) {
process(wire, left, right);
}
fclose(file);
printf("a: %hu\n", get_value(wire, "a"));
return 0;
}