Day17
This commit is contained in:
BIN
day17/c/day17
Executable file
BIN
day17/c/day17
Executable file
Binary file not shown.
179
day17/c/day17.c
Normal file
179
day17/c/day17.c
Normal file
@@ -0,0 +1,179 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define CHARS_MAX 128
|
||||
#define MAX_INSTRUCTIONS 128
|
||||
|
||||
#define BIT_JUMPED 0
|
||||
|
||||
enum {
|
||||
A,
|
||||
B,
|
||||
C,
|
||||
REGISTERS_LEN
|
||||
};
|
||||
|
||||
enum {
|
||||
ADV,
|
||||
BXL,
|
||||
BST,
|
||||
JNZ,
|
||||
BXC,
|
||||
OUT,
|
||||
BDV,
|
||||
CDV
|
||||
};
|
||||
|
||||
void execute(uint64_t registers[REGISTERS_LEN], uint8_t *instructions, uint32_t *pc, uint8_t *status, char *output_buffer, int *buf_len);
|
||||
uint64_t combo(uint64_t registers[REGISTERS_LEN], uint8_t operand);
|
||||
uint64_t revert(uint8_t *instructions_inverted, uint8_t *instructions, uint32_t instruction_count, uint64_t current_A, uint32_t i, int print_register);
|
||||
|
||||
int main() {
|
||||
char *p, *buf, c;
|
||||
|
||||
buf = calloc(CHARS_MAX, sizeof(char));
|
||||
p = buf;
|
||||
|
||||
uint64_t registers[3];
|
||||
int reading_register = 0, operand = 0;
|
||||
uint8_t *instructions = calloc(MAX_INSTRUCTIONS, sizeof(instructions[0]));
|
||||
uint32_t instruction_count = 0;
|
||||
|
||||
while ((c = getchar()) != EOF) {
|
||||
if (reading_register < 3) {
|
||||
*p++ = c;
|
||||
if (c != '\n') {
|
||||
continue;
|
||||
}
|
||||
|
||||
p = buf;
|
||||
while(*p++ != ':');
|
||||
p++;
|
||||
sscanf(p, "%li", ®isters[reading_register++]);
|
||||
|
||||
memset(buf, 0, CHARS_MAX);
|
||||
p = buf;
|
||||
} else {
|
||||
if (c < 48 || c > 57) continue;
|
||||
uint8_t num = c - 48;
|
||||
instructions[instruction_count++] = num;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t pc = 0;
|
||||
uint8_t status = 0;
|
||||
int buf_len = 0;
|
||||
while (pc < instruction_count) {
|
||||
execute(registers, instructions, &pc, &status, buf, &buf_len);
|
||||
if (!(status & (1 << BIT_JUMPED))) {
|
||||
pc += 2;
|
||||
}
|
||||
}
|
||||
|
||||
buf[buf_len - 1] = '\0';
|
||||
printf("%s\n", buf);
|
||||
|
||||
// Find print register
|
||||
int print_register = A;
|
||||
for (uint32_t i = 0; i < instruction_count; i+=2) {
|
||||
if (instructions[i] == OUT) {
|
||||
print_register = instructions[i+1] - 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Invert instruction list
|
||||
uint8_t *instructions_inverted = calloc(instruction_count, sizeof(instructions[0]));
|
||||
for (uint32_t i = 0; i < instruction_count; i++) {
|
||||
instructions_inverted[i] = instructions[instruction_count - i - 1];
|
||||
}
|
||||
|
||||
printf("%lu\n", revert(instructions_inverted, instructions, instruction_count, 0, 0, print_register));
|
||||
|
||||
|
||||
free(buf);
|
||||
free(instructions);
|
||||
free(instructions_inverted);
|
||||
}
|
||||
|
||||
uint64_t revert(uint8_t *instructions_inverted, uint8_t *instructions, uint32_t instruction_count, uint64_t current_A, uint32_t i, int print_register) {
|
||||
if (i == instruction_count) {
|
||||
return current_A >> 3;
|
||||
}
|
||||
|
||||
// Try each 3-bit LSB of A
|
||||
for (uint32_t j = 0; j < 8; j++) {
|
||||
uint64_t next_A = current_A + j;
|
||||
uint64_t registers_copy[3] = {next_A, 0, 0};
|
||||
uint32_t pc = 0;
|
||||
uint8_t status = 0;
|
||||
for (pc = 0; pc < instruction_count - 4; pc+=2) {
|
||||
execute(registers_copy, instructions, &pc, &status, NULL, NULL);
|
||||
}
|
||||
// Check print register
|
||||
uint64_t expected_output = instructions_inverted[i];
|
||||
if (registers_copy[print_register] % 8 == expected_output) {
|
||||
uint64_t a = revert(instructions_inverted, instructions, instruction_count, next_A << 3, i + 1, print_register);
|
||||
if (a) {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void execute(uint64_t registers[REGISTERS_LEN], uint8_t *instructions, uint32_t *pc, uint8_t *status, char *output_buffer, int *buf_len) {
|
||||
uint8_t opcode = instructions[*pc];
|
||||
uint8_t operand = instructions[(*pc) + 1];
|
||||
uint8_t current_status = *status;
|
||||
uint8_t next_status = 0;
|
||||
|
||||
switch (opcode) {
|
||||
case ADV:
|
||||
registers[A] = registers[A] / (1 << combo(registers, operand));
|
||||
break;
|
||||
case BXL:
|
||||
registers[B] = registers[B] ^ operand;
|
||||
break;
|
||||
case BST:
|
||||
registers[B] = combo(registers, operand) % 8;
|
||||
break;
|
||||
case JNZ:
|
||||
if (registers[A] != 0) {
|
||||
*pc = operand;
|
||||
next_status |= 1 << BIT_JUMPED;
|
||||
}
|
||||
break;
|
||||
case BXC:
|
||||
registers[B] = registers[B] ^ registers[C];
|
||||
break;
|
||||
case OUT:
|
||||
output_buffer[(*buf_len)++] = ((uint8_t)combo(registers, operand) & 7) + 48;
|
||||
output_buffer[(*buf_len)++] = ',';
|
||||
break;
|
||||
case BDV:
|
||||
registers[B] = registers[A] / combo(registers, operand);
|
||||
break;
|
||||
case CDV:
|
||||
registers[C] = registers[A] / (1 << combo(registers, operand));
|
||||
break;
|
||||
}
|
||||
|
||||
*status = next_status;
|
||||
}
|
||||
|
||||
uint64_t combo(uint64_t registers[REGISTERS_LEN], uint8_t operand) {
|
||||
if (operand < 4) {
|
||||
return operand;
|
||||
}
|
||||
|
||||
if (operand == 7) {
|
||||
printf("INVALID PROGRAM\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return registers[operand - 4];
|
||||
}
|
||||
5
day17/input.txt
Normal file
5
day17/input.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
Register A: 46187030
|
||||
Register B: 0
|
||||
Register C: 0
|
||||
|
||||
Program: 2,4,1,5,7,5,0,3,4,0,1,6,5,5,3,0
|
||||
5
day17/sample.txt
Normal file
5
day17/sample.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
Register A: 729
|
||||
Register B: 0
|
||||
Register C: 0
|
||||
|
||||
Program: 0,1,5,4,3,0
|
||||
5
day17/sample2.txt
Normal file
5
day17/sample2.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
Register A: 2024
|
||||
Register B: 0
|
||||
Register C: 0
|
||||
|
||||
Program: 0,3,5,4,3,0
|
||||
Reference in New Issue
Block a user