You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
211 lines
4.7 KiB
211 lines
4.7 KiB
6 years ago
|
#include <stdlib.h>
|
||
|
#include <stdio.h>
|
||
|
|
||
|
#include <glib.h>
|
||
|
|
||
|
#define REGS 6
|
||
|
|
||
|
typedef int reg_t;
|
||
|
|
||
|
enum instr_id {
|
||
|
INSTR_ADDR,
|
||
|
INSTR_ADDI,
|
||
|
INSTR_MULR,
|
||
|
INSTR_MULI,
|
||
|
INSTR_BANR,
|
||
|
INSTR_BANI,
|
||
|
INSTR_BORR,
|
||
|
INSTR_BORI,
|
||
|
INSTR_SETR,
|
||
|
INSTR_SETI,
|
||
|
INSTR_GTIR,
|
||
|
INSTR_GTRI,
|
||
|
INSTR_GTRR,
|
||
|
INSTR_EQIR,
|
||
|
INSTR_EQRI,
|
||
|
INSTR_EQRR,
|
||
|
INSTR_ID_COUNT
|
||
|
};
|
||
|
|
||
|
struct instr {
|
||
|
enum instr_id i;
|
||
|
int a;
|
||
|
int b;
|
||
|
int c;
|
||
|
};
|
||
|
|
||
|
const char *instr_str[] = {
|
||
|
"addr",
|
||
|
"addi",
|
||
|
"mulr",
|
||
|
"muli",
|
||
|
"banr",
|
||
|
"bani",
|
||
|
"borr",
|
||
|
"bori",
|
||
|
"setr",
|
||
|
"seti",
|
||
|
"gtir",
|
||
|
"gtri",
|
||
|
"gtrr",
|
||
|
"eqir",
|
||
|
"eqri",
|
||
|
"eqrr"
|
||
|
};
|
||
|
|
||
|
void instr_interpret(reg_t *r, struct instr *i)
|
||
|
{
|
||
|
switch (i->i) {
|
||
|
case INSTR_ADDR:
|
||
|
case INSTR_MULR:
|
||
|
case INSTR_BANR:
|
||
|
case INSTR_BORR:
|
||
|
case INSTR_GTRR:
|
||
|
case INSTR_EQRR:
|
||
|
if (i->b >= REGS) return;
|
||
|
// fallthrough
|
||
|
case INSTR_ADDI:
|
||
|
case INSTR_MULI:
|
||
|
case INSTR_BANI:
|
||
|
case INSTR_BORI:
|
||
|
case INSTR_SETR:
|
||
|
case INSTR_GTRI:
|
||
|
case INSTR_EQRI:
|
||
|
if (i->a >= REGS) return;
|
||
|
// fallthrough
|
||
|
case INSTR_SETI:
|
||
|
if (i->c >= REGS) return;
|
||
|
break;
|
||
|
|
||
|
case INSTR_GTIR:
|
||
|
case INSTR_EQIR:
|
||
|
if (i->b >= REGS) return;
|
||
|
if (i->c >= REGS) return;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
switch (i->i) {
|
||
|
case INSTR_ADDR: r[i->c] = r[i->a] + r[i->b]; break;
|
||
|
case INSTR_ADDI: r[i->c] = r[i->a] + i->b; break;
|
||
|
case INSTR_MULR: r[i->c] = r[i->a] * r[i->b]; break;
|
||
|
case INSTR_MULI: r[i->c] = r[i->a] * i->b; break;
|
||
|
case INSTR_BANR: r[i->c] = r[i->a] & r[i->b]; break;
|
||
|
case INSTR_BANI: r[i->c] = r[i->a] & i->b; break;
|
||
|
case INSTR_BORR: r[i->c] = r[i->a] | r[i->b]; break;
|
||
|
case INSTR_BORI: r[i->c] = r[i->a] | i->b; break;
|
||
|
case INSTR_SETR: r[i->c] = r[i->a]; break;
|
||
|
case INSTR_SETI: r[i->c] = i->a; break;
|
||
|
case INSTR_GTIR: r[i->c] = (i->a > r[i->b]) ? 1 : 0; break;
|
||
|
case INSTR_GTRI: r[i->c] = (r[i->a] > i->b) ? 1 : 0; break;
|
||
|
case INSTR_GTRR: r[i->c] = (r[i->a] > r[i->b]) ? 1 : 0; break;
|
||
|
case INSTR_EQIR: r[i->c] = (i->a == r[i->b]) ? 1 : 0; break;
|
||
|
case INSTR_EQRI: r[i->c] = (r[i->a] == i->b) ? 1 : 0; break;
|
||
|
case INSTR_EQRR: r[i->c] = (r[i->a] == r[i->b]) ? 1 : 0; break;
|
||
|
default: break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
struct instr *parse_instructions(const char *fname, int *len, int *ip)
|
||
|
{
|
||
|
FILE *f = fopen(fname, "r");
|
||
|
if (!f) {
|
||
|
perror(fname);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
GArray *array = g_array_new(FALSE, FALSE, sizeof(struct instr));
|
||
|
|
||
|
char *line = NULL;
|
||
|
size_t line_len = 0;
|
||
|
while (getline(&line, &line_len, f) != -1) {
|
||
|
char *args = strchr(line, ' ');
|
||
|
if (!args) continue;
|
||
|
*args++ = '\0';
|
||
|
|
||
|
if (strcmp(line, "#ip") == 0) {
|
||
|
*ip = strtol(args, NULL, 0);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
struct instr instr = {0};
|
||
|
|
||
|
for (int i = 0; i < INSTR_ID_COUNT; i++) {
|
||
|
if (strcmp(line, instr_str[i]) == 0) {
|
||
|
instr.i = i;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sscanf(args, "%d %d %d", &instr.a, &instr.b, &instr.c);
|
||
|
g_array_append_val(array, instr);
|
||
|
}
|
||
|
|
||
|
free(line);
|
||
|
fclose(f);
|
||
|
|
||
|
*len = array->len;
|
||
|
return (struct instr *)g_array_free(array, FALSE);
|
||
|
}
|
||
|
|
||
|
void print_regs(reg_t *regs, FILE *f)
|
||
|
{
|
||
|
putc('[', f);
|
||
|
for (int i = 0; i < REGS - 1; i++) {
|
||
|
fprintf(f, "%d, ", regs[i]);
|
||
|
}
|
||
|
fprintf(f, "%d]", regs[REGS - 1]);
|
||
|
}
|
||
|
|
||
|
int main(int argc, char *argv[])
|
||
|
{
|
||
|
int debug = 0;
|
||
|
if (argc > 1 && strcmp(argv[1], "-debug") == 0) debug = 1;
|
||
|
|
||
|
int ip = 0;
|
||
|
int instructions_len = 0;
|
||
|
struct instr *instructions = parse_instructions("input", &instructions_len, &ip);
|
||
|
if (!instructions) return 1;
|
||
|
if (ip >= REGS) ip = 0;
|
||
|
|
||
|
reg_t *regs = g_new0(reg_t, REGS);
|
||
|
while (regs[ip] >= 0 && regs[ip] < instructions_len) {
|
||
|
struct instr *instr = &instructions[regs[ip]];
|
||
|
|
||
|
if (debug) {
|
||
|
fprintf(stderr, "ip=%d ", regs[ip]);
|
||
|
print_regs(regs, stderr);
|
||
|
fprintf(stderr, " %s %d %d %d ",
|
||
|
instr_str[instr->i], instr->a, instr->b, instr->c);
|
||
|
}
|
||
|
|
||
|
instr_interpret(regs, instr);
|
||
|
|
||
|
if (debug) {
|
||
|
print_regs(regs, stderr);
|
||
|
putc('\n', stderr);
|
||
|
}
|
||
|
|
||
|
// Day 21 part 1 solution...
|
||
|
if (instr->i == INSTR_EQRR && (instr->a == 0 || instr->b == 0)) {
|
||
|
int reg = instr->a;
|
||
|
if (reg == 0) reg = instr->b;
|
||
|
if (reg != 0 && reg < REGS) {
|
||
|
printf("Register compared: %d\n", reg);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
regs[ip]++;
|
||
|
}
|
||
|
|
||
|
print_regs(regs, stdout);
|
||
|
putchar('\n');
|
||
|
|
||
|
free(regs);
|
||
|
free(instructions);
|
||
|
return 0;
|
||
|
}
|