diff --git a/day17/c/day17 b/day17/c/day17 new file mode 100755 index 0000000..f54a12e Binary files /dev/null and b/day17/c/day17 differ diff --git a/day17/c/day17.c b/day17/c/day17.c new file mode 100644 index 0000000..d6e40ac --- /dev/null +++ b/day17/c/day17.c @@ -0,0 +1,179 @@ +#include +#include +#include +#include + +#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]; +} diff --git a/day17/input.txt b/day17/input.txt new file mode 100644 index 0000000..2924de7 --- /dev/null +++ b/day17/input.txt @@ -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 diff --git a/day17/sample.txt b/day17/sample.txt new file mode 100644 index 0000000..f09839b --- /dev/null +++ b/day17/sample.txt @@ -0,0 +1,5 @@ +Register A: 729 +Register B: 0 +Register C: 0 + +Program: 0,1,5,4,3,0 diff --git a/day17/sample2.txt b/day17/sample2.txt new file mode 100644 index 0000000..4a91c26 --- /dev/null +++ b/day17/sample2.txt @@ -0,0 +1,5 @@ +Register A: 2024 +Register B: 0 +Register C: 0 + +Program: 0,3,5,4,3,0