2018/Day19/Day19A.c

129 lines
3.5 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
#include <assert.h>
#include <string.h>
typedef struct {
uint8_t opcode;
uint32_t a, b, c;
} Instruction;
Instruction instructions[1024];
enum {
ADDR, ADDI, MULR, MULI, BANR, BANI, BORR, BORI,
SETR, SETI, GTIR, GTRI, GTRR, EQIR, EQRI, EQRR,
IP,
};
const char *names[] = {
"addr", "addi", "mulr", "muli", "banr", "bani", "borr", "bori",
"setr", "seti", "gtir", "gtri", "gtrr", "eqir", "eqri", "eqrr",
"#ip",
};
int instruction_read(Instruction *i, FILE *file) {
char mnemonic[64] = {0};
size_t count = fscanf(file, "%s %u %u %u", mnemonic, &i->a, &i->b, &i->c);
if (count != 4 && count != 2)
return 0;
for (int opcode = 0; opcode <= IP; opcode++) {
if (strcmp(names[opcode], mnemonic) == 0) {
i->opcode = opcode;
return 1;
}
}
printf("Unknown mnemonic '%s'\n", mnemonic);
return 0;
}
void instruction_execute(const Instruction *i, uint32_t *r, uint32_t *ip, uint32_t *ip_r) {
if (*ip_r != -1)
r[*ip_r] = *ip;
switch (i->opcode) {
// Addition
case ADDR: r[i->c] = r[i->a] + r[i->b]; break;
case ADDI: r[i->c] = r[i->a] + i->b; break;
// Multiplication
case MULR: r[i->c] = r[i->a] * r[i->b]; break;
case MULI: r[i->c] = r[i->a] * i->b; break;
// Bitwise AND
case BANR: r[i->c] = (r[i->a] & r[i->b]); break;
case BANI: r[i->c] = (r[i->a] & i->b); break;
// Bitwise OR
case BORR: r[i->c] = (r[i->a] | r[i->b]); break;
case BORI: r[i->c] = (r[i->a] | i->b); break;
// Assignment
case SETR: r[i->c] = r[i->a]; break;
case SETI: r[i->c] = i->a; break;
// Greater-than testing
case GTIR: r[i->c] = (i->a > r[i->b]); break;
case GTRI: r[i->c] = (r[i->a] > i->b); break;
case GTRR: r[i->c] = (r[i->a] > r[i->b]); break;
// Equality testing
case EQIR: r[i->c] = (i->a == r[i->b]); break;
case EQRI: r[i->c] = (r[i->a] == i->b); break;
case EQRR: r[i->c] = (r[i->a] == r[i->b]); break;
case IP: *ip_r = i->a; *ip -= 1; break;
default: assert(0);
}
if (*ip_r != -1)
*ip = r[*ip_r];
*ip += 1;
}
int main(int argc, char **argv) {
if (argc != 2) {
printf("Usage: %s [input]\n", argv[0]);
return EXIT_FAILURE;
}
FILE *file = fopen(argv[1], "r");
uint32_t registers[6] = {0};
uint32_t ip_reg = -1;
size_t instr_count = 0;
for (instr_count = 0; instr_count < 1024 && instruction_read(&instructions[instr_count], file); instr_count++) {
#ifdef DEBUG
printf("opcode: %2d (%s), a: %d, b: %d, c: %d\n", instructions[instr_count].opcode,
names[instructions[instr_count].opcode], instructions[instr_count].a, instructions[instr_count].b,
instructions[instr_count].c);
#endif
}
for (uint32_t i = 0; i < instr_count;) {
Instruction instruction = instructions[i];
#ifdef DEBUG
const char *name = names[instruction.opcode];
printf("opcode: %2d (%s), a: %d, b: %d, c: %d\n", instruction.opcode,
name, instruction.a, instruction.b, instruction.c);
#endif
instruction_execute(&instruction, registers, &i, &ip_reg);
#ifdef DEBUG
printf("registers: %d %d %d %d %d %d\n", registers[0], registers[1],
registers[2], registers[3], registers[4], registers[5]);
#endif
}
fclose(file);
printf("%d\n", registers[0]);
return EXIT_SUCCESS;
}