Skip to content

Instantly share code, notes, and snippets.

@ksmigrod
Created December 17, 2024 17:59
Show Gist options
  • Save ksmigrod/a2225190a5fca120f516e55ae35efabc to your computer and use it in GitHub Desktop.
Save ksmigrod/a2225190a5fca120f516e55ae35efabc to your computer and use it in GitHub Desktop.
#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