aoc_omni/c/lib/intcode.h

167 lines
3.4 KiB
C
Raw Normal View History

2024-12-12 10:08:11 -05:00
#include <stdbool.h>
#include "./aoc.h"
#define ROM_LENGTH 1000
2024-12-12 11:05:54 -05:00
#define OUTPUT_BUFFER_LENGTH 1000
#define POSITION_MODE 0
#define IMMEDIATE_MODE 1
2024-12-12 10:08:11 -05:00
int rom[ROM_LENGTH];
int rom_count;
typedef struct IC {
int *rom;
int *data;
int program_counter;
bool halted;
2024-12-12 11:05:54 -05:00
int output_buffer[OUTPUT_BUFFER_LENGTH];
int output_buffer_count;
2024-12-12 10:08:11 -05:00
} IC;
int ic_peek(IC *c, int address) {
return c->data[address];
}
void ic_poke(IC *c, int address, int value) {
c->data[address] = value;
}
int ic_read(IC *c) {
return ic_peek(c, c->program_counter++);
}
void ic_write(IC *c, int value) {
ic_poke(c, ic_peek(c, c->program_counter++), value);
}
void ic_halt(IC *c) {
c->halted = true;
}
2024-12-12 11:05:54 -05:00
void ic_instruction_add(IC *c, int modes) {
bool x_mode = modes % 10;
modes /= 10;
bool y_mode = modes % 10;
modes /= 10;
2024-12-12 10:08:11 -05:00
int x = ic_read(c);
2024-12-12 11:05:54 -05:00
if (x_mode == POSITION_MODE) x = ic_peek(c, x);
2024-12-12 10:08:11 -05:00
int y = ic_read(c);
2024-12-12 11:05:54 -05:00
if (y_mode == POSITION_MODE) y = ic_peek(c, y);
ic_write(c, x + y);
2024-12-12 10:08:11 -05:00
}
2024-12-12 11:05:54 -05:00
void ic_instruction_multiply(IC *c, int modes) {
bool x_mode = modes % 10;
modes /= 10;
bool y_mode = modes % 10;
modes /= 10;
2024-12-12 10:08:11 -05:00
int x = ic_read(c);
2024-12-12 11:05:54 -05:00
if (x_mode == POSITION_MODE) x = ic_peek(c, x);
2024-12-12 10:08:11 -05:00
int y = ic_read(c);
2024-12-12 11:05:54 -05:00
if (y_mode == POSITION_MODE) y = ic_peek(c, y);
ic_write(c, x * y);
2024-12-12 10:08:11 -05:00
}
2024-12-12 11:05:54 -05:00
void ic_instruction_input(IC *c, int _modes) {
ic_write(c, 1);
}
void ic_instruction_output(IC *c, int modes) {
if (c->output_buffer_count >= OUTPUT_BUFFER_LENGTH) {
printf("Output buffer overflow!\n");
ic_halt(c);
}
int mode = modes % 10;
modes /= 10;
int to_output = ic_read(c);
if (mode == POSITION_MODE) to_output = ic_peek(c, to_output);
c->output_buffer[c->output_buffer_count++] = to_output;
}
void ic_instruction_halt(IC *c, int _modes) {
2024-12-12 10:08:11 -05:00
ic_halt(c);
}
int ic_execute_instruction(IC *c) {
2024-12-12 11:05:54 -05:00
int instruction = ic_read(c);
int opcode = instruction % 100;
int modes = instruction / 100;
// printf("Running %d: opcode %d with modes %d\n", instruction, opcode, modes);
// printf("PC: %d\n", c->program_counter - 1);
2024-12-12 10:08:11 -05:00
switch(opcode) {
case 1:
2024-12-12 11:05:54 -05:00
ic_instruction_add(c, modes);
2024-12-12 10:08:11 -05:00
break;
case 2:
2024-12-12 11:05:54 -05:00
ic_instruction_multiply(c, modes);
break;
case 3:
ic_instruction_input(c, modes);
break;
case 4:
ic_instruction_output(c, modes);
2024-12-12 10:08:11 -05:00
break;
case 99:
2024-12-12 11:05:54 -05:00
ic_instruction_halt(c, modes);
2024-12-12 10:08:11 -05:00
break;
default:
printf("Invalid opcode [%d] encountered at %d\n", opcode, c->program_counter - 1);
2024-12-12 11:05:54 -05:00
ic_instruction_halt(c, 0);
2024-12-12 10:08:11 -05:00
break;
}
}
void ic_print(IC *c) {
printf("PC: %d\n", c->program_counter);
2024-12-12 11:05:54 -05:00
2024-12-12 10:08:11 -05:00
for (int i = 0; i < rom_count; i++) {
printf("%6d ", c->data[i]);
if (i % 8 == 7) printf("\n");
}
printf("\n");
2024-12-12 11:05:54 -05:00
printf("Output buffer: ");
for (int i = 0; i < c->output_buffer_count; i++) {
printf("[%d] ", c->output_buffer[i]);
}
printf("\n");
2024-12-12 10:08:11 -05:00
}
void ic_reset(IC *c) {
memcpy(c->data, c->rom, rom_count * sizeof(int));
c->program_counter = 0;
c->halted = true;
2024-12-12 11:05:54 -05:00
c->output_buffer_count = 0;
2024-12-12 10:08:11 -05:00
}
void ic_run(IC *c) {
c->halted = false;
while (!c->halted) ic_execute_instruction(c);
}
IC *ic_new_computer(void) {
IC *c = malloc(sizeof(IC));
c->rom = rom;
c->data = malloc(rom_count * sizeof(int));
ic_reset(c);
return c;
}
int ic_load_rom_from_input(void) {
char *input = aoc_read_input();
char *token = strtok(input, ",");
while (token != NULL) {
rom[rom_count++] = atoi(token);
token = strtok(NULL, ",");
}
return rom_count;
}