-
-
Save ksmigrod/a2225190a5fca120f516e55ae35efabc to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdint.h> | |
#include <stdlib.h> | |
#include <string.h> | |
typedef struct cpu_t | |
{ | |
uint64_t regA; | |
uint64_t regB; | |
uint64_t regC; | |
size_t ip; | |
uint8_t mem[256]; | |
size_t mem_size; | |
uint8_t output[256]; | |
size_t output_size; | |
} cpu_t; | |
static void soft_reset(cpu_t *cpu, uint64_t regA) | |
{ | |
cpu->regA = regA; | |
cpu->ip = 0; | |
cpu->output_size = 0; | |
} | |
static bool is_partial(cpu_t *cpu, size_t expected_size) | |
{ | |
size_t offset = cpu->mem_size - cpu->output_size; | |
if (expected_size < offset) return false; | |
for (size_t i = 0; i < cpu->output_size; i++) { | |
if (cpu->mem[offset + i] != cpu->output[i]) { | |
return false; | |
} | |
} | |
return true; | |
} | |
static bool is_halted(cpu_t *cpu) | |
{ | |
return cpu->ip >= cpu->mem_size; | |
} | |
static uint8_t next(cpu_t* cpu) | |
{ | |
return cpu->mem[cpu->ip++]; | |
} | |
static unsigned int combo(const cpu_t* cpu, uint8_t val) | |
{ | |
switch (val) { | |
case 0: | |
case 1: | |
case 2: | |
case 3: | |
return val; | |
case 4: | |
return cpu->regA; | |
case 5: | |
return cpu->regB; | |
case 6: | |
return cpu->regC; | |
default: | |
fprintf(stderr, "Invalid combo value: %hhu\n", val); | |
exit(EXIT_FAILURE); | |
} | |
} | |
static uint64_t Xdv(cpu_t* cpu, uint8_t val) | |
{ | |
return cpu->regA / (1 << combo(cpu, val)); | |
} | |
static void adv(cpu_t* cpu, uint8_t val) | |
{ | |
cpu->regA = Xdv(cpu, val); | |
} | |
static void bdv(cpu_t* cpu, uint8_t val) | |
{ | |
cpu->regB = Xdv(cpu, val); | |
} | |
static void cdv(cpu_t* cpu, uint8_t val) | |
{ | |
cpu->regC = Xdv(cpu, val); | |
} | |
static void bxl(cpu_t* cpu, uint8_t val) | |
{ | |
cpu->regB ^= val; | |
} | |
static void bst(cpu_t* cpu, uint8_t val) | |
{ | |
cpu->regB = combo(cpu, val) % 8; | |
} | |
static void bxc(cpu_t* cpu, uint8_t __unused) | |
{ | |
cpu->regB ^= cpu->regC; | |
} | |
void out(cpu_t* cpu, uint8_t val) | |
{ | |
cpu->output[cpu->output_size++] = combo(cpu, val) % 8; | |
} | |
void jnz(cpu_t* cpu, uint8_t val) | |
{ | |
if (cpu->regA != 0) { | |
cpu->ip = val; | |
} | |
} | |
void (*instructions[])(cpu_t* cpu, uint8_t arg) = { | |
adv, bxl, bst, jnz, bxc, out, bdv, cdv | |
}; | |
bool simulate(cpu_t* cpu, uint64_t regA, size_t expected_size) | |
{ | |
soft_reset(cpu, regA); | |
while (!is_halted(cpu)) { | |
uint8_t instr = next(cpu); | |
uint8_t arg = next(cpu); | |
instructions[instr](cpu, arg); | |
} | |
return is_partial(cpu, expected_size); | |
} | |
void read_state(cpu_t* cpu) | |
{ | |
scanf("Register A: %llu\nRegister B: %llu\nRegister C: %llu\n\nProgram: ", | |
&cpu->regA, &cpu->regB, &cpu->regC); | |
cpu->mem_size = 0; | |
char line[256]; | |
fgets(line, sizeof(line), stdin); | |
char* token = strtok(line, ","); | |
while (token != NULL) { | |
cpu->mem[cpu->mem_size++] = atoi(token); | |
token = strtok(NULL, ","); | |
} | |
cpu->ip = 0; | |
} | |
const uint64_t nums[] = {2,4,1,7,7,5,1,7,0,3,4,1,5,5,3,0}; | |
const size_t nums_size = sizeof(nums) / sizeof(nums[0]); | |
static uint64_t get_digit(uint64_t a) | |
{ | |
uint64_t b = a % 8; | |
b ^= 7; | |
uint64_t c = a / (1 << b); | |
b ^= 7; | |
b = b ^ c; | |
return b % 8; | |
} | |
static void match(cpu_t *cpu, int level, uint64_t obj) | |
{ | |
if (level < 0) { | |
printf("%llo %llu\n", obj, obj); | |
return; | |
} | |
for (uint64_t i = 0; i < 8; i++) { | |
const uint64_t a = (obj << 3) + i; | |
if (simulate(cpu, a, level)) { | |
match(cpu, level - 1, a); | |
} | |
} | |
} | |
int main(void) | |
{ | |
cpu_t cpu; | |
read_state(&cpu); | |
match(&cpu, 15, 0); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment