176 lines
4.4 KiB
C
176 lines
4.4 KiB
C
#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;
|
|
}
|