From 307e9909248e6d04e80c117852779c1fcddd5a4b Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Thu, 19 Dec 2024 23:48:06 -0600 Subject: [PATCH] 2024 day17 (incomplete) --- 2024/day16/solution.c | 6 +- 2024/day17/input.txt | 5 + 2024/day17/input.txt.h | 15 +++ 2024/day17/sample1.txt | 5 + 2024/day17/sample1.txt.h | 15 +++ 2024/day17/sample2.txt | 5 + 2024/day17/sample2.txt.h | 15 +++ 2024/day17/solution.c | 243 +++++++++++++++++++++++++++++++++++++++ dijkstra.c | 6 +- input_dreamcast.inc | 11 ++ runner.c | 2 +- runner.inc | 7 ++ solutions.mk | 6 +- 13 files changed, 334 insertions(+), 7 deletions(-) create mode 100644 2024/day17/input.txt create mode 100644 2024/day17/input.txt.h create mode 100644 2024/day17/sample1.txt create mode 100644 2024/day17/sample1.txt.h create mode 100644 2024/day17/sample2.txt create mode 100644 2024/day17/sample2.txt.h create mode 100644 2024/day17/solution.c diff --git a/2024/day16/solution.c b/2024/day16/solution.c index baed3fe..50909bf 100644 --- a/2024/day16/solution.c +++ b/2024/day16/solution.c @@ -1,7 +1,7 @@ #include -#include -//#include "printf.h" +//#include +#include "printf.h" #include "dijkstra.h" #include "memory.h" @@ -95,6 +95,7 @@ int64_t _2024_day16_part2(const char * input, int length) return -1; } +/* #include int main() @@ -107,3 +108,4 @@ int main() fclose(f); printf("%ld\n", _2024_day16_part1(buf, length)); } +*/ diff --git a/2024/day17/input.txt b/2024/day17/input.txt new file mode 100644 index 0000000..cbd9ed7 --- /dev/null +++ b/2024/day17/input.txt @@ -0,0 +1,5 @@ +Register A: 59397658 +Register B: 0 +Register C: 0 + +Program: 2,4,1,1,7,5,4,6,1,4,0,3,5,5,3,0 diff --git a/2024/day17/input.txt.h b/2024/day17/input.txt.h new file mode 100644 index 0000000..86ea6a4 --- /dev/null +++ b/2024/day17/input.txt.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern uint32_t _binary_2024_day17_input_txt_start __asm("_binary_2024_day17_input_txt_start"); +extern uint32_t _binary_2024_day17_input_txt_end __asm("_binary_2024_day17_input_txt_end"); +extern uint32_t _binary_2024_day17_input_txt_size __asm("_binary_2024_day17_input_txt_size"); + +#ifdef __cplusplus +} +#endif diff --git a/2024/day17/sample1.txt b/2024/day17/sample1.txt new file mode 100644 index 0000000..f09839b --- /dev/null +++ b/2024/day17/sample1.txt @@ -0,0 +1,5 @@ +Register A: 729 +Register B: 0 +Register C: 0 + +Program: 0,1,5,4,3,0 diff --git a/2024/day17/sample1.txt.h b/2024/day17/sample1.txt.h new file mode 100644 index 0000000..27f1995 --- /dev/null +++ b/2024/day17/sample1.txt.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern uint32_t _binary_2024_day17_sample1_txt_start __asm("_binary_2024_day17_sample1_txt_start"); +extern uint32_t _binary_2024_day17_sample1_txt_end __asm("_binary_2024_day17_sample1_txt_end"); +extern uint32_t _binary_2024_day17_sample1_txt_size __asm("_binary_2024_day17_sample1_txt_size"); + +#ifdef __cplusplus +} +#endif diff --git a/2024/day17/sample2.txt b/2024/day17/sample2.txt new file mode 100644 index 0000000..4a91c26 --- /dev/null +++ b/2024/day17/sample2.txt @@ -0,0 +1,5 @@ +Register A: 2024 +Register B: 0 +Register C: 0 + +Program: 0,3,5,4,3,0 diff --git a/2024/day17/sample2.txt.h b/2024/day17/sample2.txt.h new file mode 100644 index 0000000..98d8764 --- /dev/null +++ b/2024/day17/sample2.txt.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern uint32_t _binary_2024_day17_sample2_txt_start __asm("_binary_2024_day17_sample2_txt_start"); +extern uint32_t _binary_2024_day17_sample2_txt_end __asm("_binary_2024_day17_sample2_txt_end"); +extern uint32_t _binary_2024_day17_sample2_txt_size __asm("_binary_2024_day17_sample2_txt_size"); + +#ifdef __cplusplus +} +#endif diff --git a/2024/day17/solution.c b/2024/day17/solution.c new file mode 100644 index 0000000..9de3f6c --- /dev/null +++ b/2024/day17/solution.c @@ -0,0 +1,243 @@ +#include + +#include "printf.h" +#include "parse.h" + +struct state { + int pc; + int64_t a; + int64_t b; + int64_t c; + char mem[256]; + int mem_length; + char out[256]; + int out_length; +}; + +static int64_t combo_operand(struct state * state, int operand) +{ + switch (operand) { + case 0: return 0; + case 1: return 1; + case 2: return 2; + case 3: return 3; + case 4: return state->a; + case 5: return state->b; + case 6: return state->c; + default: + printf("invalid combo operand %d\n", operand); + return -1; + } +} + +static bool op_adv(struct state * state, int operand) +{ + int64_t value = combo_operand(state, operand); + const int64_t one = 1; + state->a = state->a / (one << value); + return true; +} + +static bool op_bxl(struct state * state, int operand) +{ + state->b = state->b ^ (int64_t)operand; + return true; +} + +static bool op_bst(struct state * state, int operand) +{ + int64_t value = combo_operand(state, operand); + state->b = value % 8; + return true; +} + +static bool op_jnz(struct state * state, int operand) +{ + if (state->a != 0) { + state->pc = operand; + return false; + } else { + return true; + } +} + +static bool op_bxc(struct state * state, int operand) +{ + state->b = state->b ^ state->c; + return true; +} + +static bool op_out(struct state * state, int operand) +{ + int64_t value = combo_operand(state, operand); + state->out[state->out_length++] = value % 8; + return true; +} + +static bool op_bdv(struct state * state, int operand) +{ + int64_t value = combo_operand(state, operand); + state->b = state->a / (1 << value); + return true; +} + +static bool op_cdv(struct state * state, int operand) +{ + int64_t value = combo_operand(state, operand); + state->c = state->a / (1 << value); + return true; +} + +static const char * parse_register(const char * input, char c, int * value) +{ + input = parse_match(input, "Register "); + input = parse_skip(input, c); + input = parse_match(input, ": "); + input = parse_base10(input, value); + input = parse_skip(input, '\n'); + return input; +} + +static void step(struct state * state) +{ + int op = state->mem[state->pc]; + int operand = state->mem[state->pc+1]; + bool incpc; + switch (op) { + case 0: incpc = op_adv(state, operand); break; + case 1: incpc = op_bxl(state, operand); break; + case 2: incpc = op_bst(state, operand); break; + case 3: incpc = op_jnz(state, operand); break; + case 4: incpc = op_bxc(state, operand); break; + case 5: incpc = op_out(state, operand); break; + case 6: incpc = op_bdv(state, operand); break; + case 7: incpc = op_cdv(state, operand); break; + default: + printf("invalid opcode %d\n", op); + return; + } + if (incpc) + state->pc = state->pc + 2; +} + +static const char * parse_program(const char * input, const char * end, struct state * state) +{ + input = parse_match(input, "Program: "); + + int value; + state->mem_length = 0; + input = parse_base10(input, &value); + state->mem[state->mem_length++] = value; + while (input < end) { + input = parse_skip(input, ','); + input = parse_base10(input, &value); + state->mem[state->mem_length++] = value; + input = parse_skip(input, '\n'); + } + return input; +} + +static inline void run_until_halt(struct state * state) +{ + while (state->pc < state->mem_length) { + step(state); + } +} + +static void parse_input(const char * input, int length, struct state * state) +{ + const char * end = input + length; + + state->pc = 0; + state->out_length = 0; + + int reg; + input = parse_register(input, 'A', ®); + state->a = reg; + input = parse_register(input, 'B', ®); + state->b = reg; + input = parse_register(input, 'C', ®); + state->c = reg; + + input = parse_skip(input, '\n'); + parse_program(input, end, state); +} + +static void print_out(struct state * state) +{ + printf("%d", state->out[0]); + for (int i = 1; i < state->out_length; i++) { + printf(",%d", state->out[i]); + } + print_char('\n'); +} + +int64_t _2024_day17_part1(const char * input, int length) +{ + struct state state; + parse_input(input, length, &state); + + run_until_halt(&state); + print_out(&state); + + return -1; +} + +static inline bool out_eq_mem(const struct state * state) +{ + if (state->mem_length != state->out_length) { + return false; + } + + for (int i = 0; i < state->mem_length; i++) { + if (state->mem[i] != state->out[i]) { + return false; + } + } + return true; +} + +int64_t _2024_day17_part2(const char * input, int length) +{ + struct state state; + parse_input(input, length, &state); + + int64_t a = 1; + int64_t last_a = a; + while (true) { + state.a = a; + state.b = 0; + state.c = 0; + state.pc = 0; + state.out_length = 0; + + run_until_halt(&state); + + if (state.out_length < state.mem_length) { + last_a = a; + a *= 2; + } else { + break; + } + } + + a = last_a; + while (true) { + state.a = a; + state.b = 0; + state.c = 0; + state.pc = 0; + state.out_length = 0; + + run_until_halt(&state); + + if (out_eq_mem(&state)) + break; + + a += 1; + } + + print_out(&state); + + return a; +} diff --git a/dijkstra.c b/dijkstra.c index 5fa014f..0a04ba3 100644 --- a/dijkstra.c +++ b/dijkstra.c @@ -2,10 +2,10 @@ #include "dijkstra.h" #include "heap.h" #include "memory.h" -//#include "printf.h" +#include "printf.h" -#include -#include +//#include +//#include void dijkstra_cartesian(const char * graph, int stride, diff --git a/input_dreamcast.inc b/input_dreamcast.inc index 509e45f..00f7988 100644 --- a/input_dreamcast.inc +++ b/input_dreamcast.inc @@ -43,6 +43,9 @@ #include "2024/day15/input.txt.h" #include "2024/day16/sample1.txt.h" #include "2024/day16/input.txt.h" +#include "2024/day17/sample1.txt.h" +#include "2024/day17/sample2.txt.h" +#include "2024/day17/input.txt.h" static struct start_size sample[][2] = { { @@ -171,6 +174,12 @@ static struct start_size sample[][2] = { { ( char *)&_binary_2024_day16_sample1_txt_start, (uint32_t)&_binary_2024_day16_sample1_txt_size }, }, + { + { ( char *)&_binary_2024_day17_sample1_txt_start, + (uint32_t)&_binary_2024_day17_sample1_txt_size }, + { ( char *)&_binary_2024_day17_sample2_txt_start, + (uint32_t)&_binary_2024_day17_sample2_txt_size }, + }, }; static struct start_size input[] = { @@ -216,4 +225,6 @@ static struct start_size input[] = { (uint32_t)&_binary_2024_day15_input_txt_size }, { ( char *)&_binary_2024_day16_input_txt_start, (uint32_t)&_binary_2024_day16_input_txt_size }, + { ( char *)&_binary_2024_day17_input_txt_start, + (uint32_t)&_binary_2024_day17_input_txt_size }, }; diff --git a/runner.c b/runner.c index 32f8ed4..db0b757 100644 --- a/runner.c +++ b/runner.c @@ -38,7 +38,7 @@ bool runner_tick(struct runner_state * runner_state) int year = solution[ix].year; int day = solution[ix].day; - if (year != 2024 || day != 16) { + if (year != 2024 || day != 17) { return false; } diff --git a/runner.inc b/runner.inc index 3b5efcb..cc592a8 100644 --- a/runner.inc +++ b/runner.inc @@ -46,6 +46,8 @@ int64_t _2024_day15_part1(const char * input, int length); int64_t _2024_day15_part2(const char * input, int length); int64_t _2024_day16_part1(const char * input, int length); int64_t _2024_day16_part2(const char * input, int length); +int64_t _2024_day17_part1(const char * input, int length); +int64_t _2024_day17_part2(const char * input, int length); struct day_funcs solution[] = { { @@ -153,4 +155,9 @@ struct day_funcs solution[] = { {_2024_day16_part1, _2024_day16_part2}, NULL, }, + { + 2024, 17, + {_2024_day17_part1, _2024_day17_part2}, + NULL, + }, }; diff --git a/solutions.mk b/solutions.mk index 8aac665..441c325 100644 --- a/solutions.mk +++ b/solutions.mk @@ -66,4 +66,8 @@ DAY_OBJ = \ 2024/day15/solution.o \ 2024/day16/sample1.txt.o \ 2024/day16/input.txt.o \ - 2024/day16/solution.o + 2024/day16/solution.o \ + 2024/day17/sample1.txt.o \ + 2024/day17/sample2.txt.o \ + 2024/day17/input.txt.o \ + 2024/day17/solution.o