146 lines
3.5 KiB
C
146 lines
3.5 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdbool.h>
|
|
#include <limits.h>
|
|
|
|
#include "../../lib/aoc.h"
|
|
|
|
#define PROGRAM_LENGTH 16
|
|
|
|
typedef struct Computer {
|
|
long a;
|
|
long b;
|
|
long c;
|
|
long program[PROGRAM_LENGTH];
|
|
int pc;
|
|
long output[1000];
|
|
int output_count;
|
|
} Computer;
|
|
|
|
long combo(Computer *c, int operand) {
|
|
switch (operand) {
|
|
case 0:
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
return operand;
|
|
case 4:
|
|
return c->a;
|
|
case 5:
|
|
return c->b;
|
|
case 6:
|
|
return c->c;
|
|
default:
|
|
printf("Invalid operand %d detected\n", operand);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
void step(Computer *c) {
|
|
int instruction = c->program[c->pc++];
|
|
int operand = c->program[c->pc++];
|
|
// printf("%d|%d\n", instruction, operand);
|
|
// printf("a: %d, b: %d, c: %d, pc: %d\n", c->a, c->b, c->c, c->pc);
|
|
switch(instruction) {
|
|
case 0:
|
|
// printf("0: a = %d / %d = %d\n", c->a, 1<<combo(c, operand), c->a / (1<<combo(c, operand)));
|
|
c->a = c->a / (1 << combo(c, operand));
|
|
break;
|
|
case 1:
|
|
// printf("1: b = %d ^ %d = %d\n", c->b, operand, c->b ^ operand);
|
|
c->b = operand ^ c->b;
|
|
break;
|
|
case 2:
|
|
// printf("2: b = %d % 8 = %d\n", combo(c, operand), combo(c, operand) % 8);
|
|
c->b = combo(c, operand) % 8;
|
|
break;
|
|
case 3:
|
|
// printf("3: if %d then jump to %d\n", c->a, operand);
|
|
if (c->a) c->pc = operand;
|
|
break;
|
|
case 4:
|
|
// printf("4: b = %d ^ %d = %d\n", c->b, c->c, c->b ^ c->c);
|
|
c->b = c->b ^ c->c;
|
|
break;
|
|
case 5:
|
|
// printf("5: print %d\n", combo(c, operand) % 8);
|
|
c->output[c->output_count++] = combo(c, operand) % 8;
|
|
break;
|
|
case 6:
|
|
// printf("6: b = %d / %d = %d\n", c->b, 1<<combo(c, operand), c->b / (1<<combo(c, operand)));
|
|
c->b = c->a / (1 << combo(c, operand));
|
|
break;
|
|
case 7:
|
|
// printf("7: c = %d / %d = %d\n", c->a, 1<<combo(c, operand), c->a / (1<<combo(c, operand)));
|
|
c->c = c->a / (1 << combo(c, operand));
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool quine(Computer *c, long a) {
|
|
if (a % 100000000 == 0) printf("%ld\n", a);
|
|
c->a = a;
|
|
c->b = 0;
|
|
c->c = 0;
|
|
c->pc = 0;
|
|
c->output_count = 0;
|
|
while (c->pc < PROGRAM_LENGTH) {
|
|
step(c);
|
|
if (c->output_count == 0) continue;
|
|
if (c->output[c->output_count - 1] != c->program[c->output_count - 1]) return false;
|
|
}
|
|
if (c->output_count != PROGRAM_LENGTH) return false;
|
|
for (int i = 0; i < c->output_count; c++) {
|
|
if (c->program[i] != c->output[i]) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
int main() {
|
|
printf("%s\n", aoc_read_input());
|
|
Computer c;
|
|
c.pc = 0;
|
|
|
|
sscanf(aoc_read_line(), "Register A: %d", &(c.a));
|
|
sscanf(aoc_read_line(), "Register B: %d", &(c.b));
|
|
sscanf(aoc_read_line(), "Register C: %d", &(c.c));
|
|
aoc_read_line();
|
|
strtok(aoc_read_line(), " ");
|
|
for (char *token = strtok(NULL, ","); token != NULL; token = strtok(NULL, ",")) {
|
|
c.program[c.pc++] = atoi(token);
|
|
}
|
|
c.pc = 0;
|
|
c.output_count = 0;
|
|
|
|
while (c.pc < PROGRAM_LENGTH) {
|
|
printf("a: %d, b: %d, c: %d, pc: %d\n", c.a, c.b, c.c, c.pc);
|
|
step(&c);
|
|
// printf("\n");
|
|
}
|
|
|
|
printf("Part 1: %d", c.output[0]);
|
|
for (int i = 1; i < c.output_count; i++) {
|
|
printf(",%d", c.output[i]);
|
|
}
|
|
printf("\n");
|
|
|
|
//long a = 100000000000000;
|
|
// long a = 8 ** 15;
|
|
// long a = 2 ** 45;
|
|
long a = 1l << 45l;
|
|
for (; a < (1l << 48l); a++) {
|
|
quine(&c, a);
|
|
/*printf("%ld: ", a);
|
|
for (int i = 0; i < c.output_count; i++) {
|
|
printf("%ld,", c.output[i]);
|
|
}
|
|
printf("\n");*/
|
|
}
|
|
// while (!quine(&c, a)) a++;
|
|
printf("Part 2: %ld", a);
|
|
|
|
aoc_free();
|
|
exit(0);
|
|
}
|