178 lines
3.8 KiB
C
178 lines
3.8 KiB
C
#include <stdbool.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "../lib/util.h"
|
|
|
|
#define NUM_INSTRUCTIONS 654
|
|
|
|
typedef enum InstructionType {
|
|
NOP,
|
|
ACC,
|
|
JMP
|
|
} InstructionType;
|
|
|
|
typedef struct Instruction {
|
|
InstructionType type;
|
|
int argument;
|
|
} Instruction;
|
|
|
|
typedef struct Console {
|
|
size_t pc;
|
|
int acc;
|
|
Instruction program[NUM_INSTRUCTIONS];
|
|
bool visited_instructions[NUM_INSTRUCTIONS];
|
|
} Console;
|
|
|
|
void parse_instruction(char *text, Instruction *i) {
|
|
switch (*text) {
|
|
case 'n':
|
|
i->type = NOP;
|
|
break;
|
|
case 'a':
|
|
i->type = ACC;
|
|
break;
|
|
case 'j':
|
|
i->type = JMP;
|
|
break;
|
|
default:
|
|
fprintf(stderr, "FATAL: Illegal instruction %s\n", text);
|
|
exit(1);
|
|
}
|
|
|
|
i->argument = atoi(text + 4);
|
|
}
|
|
|
|
void console_step(Console *console) {
|
|
Instruction i = console->program[console->pc];
|
|
switch(i.type) {
|
|
case NOP:
|
|
console->pc++;
|
|
break;
|
|
case ACC:
|
|
console->pc++;
|
|
console->acc += i.argument;
|
|
break;
|
|
case JMP:
|
|
console->pc += i.argument;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void console_print(Console *console) {
|
|
printf("PC: %d, acc: %d\n", console->pc, console->acc);
|
|
}
|
|
|
|
void console_reset(Console *console) {
|
|
console->acc = 0;
|
|
console->pc = 0;
|
|
}
|
|
|
|
void console_run_until_loop(Console *console) {
|
|
for (int i = 0; i < NUM_INSTRUCTIONS; i++) {
|
|
console->visited_instructions[i] = false;
|
|
}
|
|
|
|
while (!console->visited_instructions[console->pc]) {
|
|
console->visited_instructions[console->pc] = true;
|
|
console_step(console);
|
|
}
|
|
}
|
|
|
|
// true = overflow
|
|
bool console_run_until_loop_or_overflow(Console *console) {
|
|
for (int i = 0; i < NUM_INSTRUCTIONS; i++) {
|
|
console->visited_instructions[i] = false;
|
|
}
|
|
|
|
while (!console->visited_instructions[console->pc]) {
|
|
console->visited_instructions[console->pc] = true;
|
|
console_step(console);
|
|
if (console->pc >= NUM_INSTRUCTIONS) return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool console_is_current_instruction_corrupted(Console *console) {
|
|
Instruction i = console->program[console->pc];
|
|
printf("%d\n", i.type);
|
|
fflush(stdout);
|
|
switch(i.type) {
|
|
case NOP:
|
|
return console->pc + i.argument > NUM_INSTRUCTIONS - 7;
|
|
case ACC:
|
|
return false;
|
|
case JMP:
|
|
return console->pc == NUM_INSTRUCTIONS || console->pc == 648;
|
|
}
|
|
}
|
|
|
|
void console_run_until_corruption(Console *console) {
|
|
int corruption_index = 0;
|
|
for (int i = 0; i < NUM_INSTRUCTIONS; i++) {
|
|
Instruction *inst = &(console->program[i]);
|
|
if (inst->type == ACC) continue;
|
|
if (inst->type == NOP) {
|
|
inst->type = JMP;
|
|
if (console_run_until_loop_or_overflow(console)) return;
|
|
inst->type = NOP;
|
|
console_reset(console);
|
|
} else {
|
|
inst->type = NOP;
|
|
if (console_run_until_loop_or_overflow(console)) return;
|
|
inst->type = JMP;
|
|
console_reset(console);
|
|
}
|
|
}
|
|
}
|
|
|
|
int part_1() {
|
|
Console *console = malloc(sizeof(Console));
|
|
console_reset(console);
|
|
char *data_buffer = load_input();
|
|
|
|
char *instruction_text = strtok(data_buffer, "\n");
|
|
|
|
do {
|
|
Instruction *inst = &(console->program[console->pc++]);
|
|
parse_instruction(instruction_text, inst);
|
|
} while (instruction_text = strtok(NULL, "\n"));
|
|
|
|
console_reset(console);
|
|
console_run_until_loop(console);
|
|
|
|
int answer = console->acc;
|
|
free(console);
|
|
free(data_buffer);
|
|
return answer;
|
|
}
|
|
|
|
int part_2() {
|
|
Console *console = malloc(sizeof(Console));
|
|
console_reset(console);
|
|
char *data_buffer = load_input();
|
|
|
|
char *instruction_text = strtok(data_buffer, "\n");
|
|
|
|
console_reset(console);
|
|
do {
|
|
Instruction *inst = &(console->program[console->pc++]);
|
|
parse_instruction(instruction_text, inst);
|
|
} while (instruction_text = strtok(NULL, "\n"));
|
|
|
|
console_reset(console);
|
|
console_run_until_corruption(console);
|
|
|
|
int answer = console->acc;
|
|
free(console);
|
|
free(data_buffer);
|
|
return answer;
|
|
}
|
|
|
|
int main() {
|
|
printf("Part 1: %d\n", part_1());
|
|
printf("Part 2: %d\n", part_2());
|
|
}
|