diff --git a/Makefile b/Makefile index c0ab356..9640eb2 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ all: $(patsubst %.cpp,%.elf,$(wildcard example/*.cpp)) -OPT = -Og +OPT = -O3 include dreamcast/base.mk include dreamcast/common.mk diff --git a/aoc.mk b/aoc.mk index c9ed242..cde2a6c 100644 --- a/aoc.mk +++ b/aoc.mk @@ -20,6 +20,10 @@ DREAMCAST_OBJ = \ $(LIB)/font/dejavusansmono/dejavusansmono.data.o \ $(LIB)/sh7091/serial.o \ $(LIB)/maple/maple.o +# libgcc/_divdi3.o \ +# libgcc/_moddi3.o \ +# libgcc/_udiv_qrnnd_16.o \ +# libgcc/_clz.o include solutions.mk diff --git a/day11/input.txt b/day11/input.txt new file mode 100644 index 0000000..ca46e95 --- /dev/null +++ b/day11/input.txt @@ -0,0 +1 @@ +70949 6183 4 3825336 613971 0 15 182 diff --git a/day11/input.txt.h b/day11/input.txt.h new file mode 100644 index 0000000..122c594 --- /dev/null +++ b/day11/input.txt.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern uint32_t _binary_day11_input_txt_start __asm("_binary_day11_input_txt_start"); +extern uint32_t _binary_day11_input_txt_end __asm("_binary_day11_input_txt_end"); +extern uint32_t _binary_day11_input_txt_size __asm("_binary_day11_input_txt_size"); + +#ifdef __cplusplus +} +#endif diff --git a/day11/sample1.txt b/day11/sample1.txt new file mode 100644 index 0000000..9b26c84 --- /dev/null +++ b/day11/sample1.txt @@ -0,0 +1 @@ +125 17 diff --git a/day11/sample1.txt.h b/day11/sample1.txt.h new file mode 100644 index 0000000..eccd574 --- /dev/null +++ b/day11/sample1.txt.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern uint32_t _binary_day11_sample1_txt_start __asm("_binary_day11_sample1_txt_start"); +extern uint32_t _binary_day11_sample1_txt_end __asm("_binary_day11_sample1_txt_end"); +extern uint32_t _binary_day11_sample1_txt_size __asm("_binary_day11_sample1_txt_size"); + +#ifdef __cplusplus +} +#endif diff --git a/day11/solution.c b/day11/solution.c new file mode 100644 index 0000000..4e79e91 --- /dev/null +++ b/day11/solution.c @@ -0,0 +1,172 @@ +#include + +#include "parse.h" +#include "unparse.h" +#include "printf.h" + +static void split_base10(int64_t n, int digits, int64_t * a, int64_t * b) +{ + int pow = 1; + digits /= 2; + while (digits-- > 0) + pow *= 10; + int64_t split = pow; + *a = n / split; + *b = n % split; +} + +static int stone_rule(int64_t n, int64_t * a, int64_t * b) +{ + int digits; + if (n == 0) { + *a = 1; + return 1; + } else if ((digits = digits_base10_64(n)) % 2 == 0) { + split_base10(n, digits, a, b); + return 2; + } else { + *a = n * 2024; + return 1; + } +} + +struct entry { + int64_t n; + int32_t depth; + int32_t _; + int64_t value; +}; + +#define CACHE_LENGTH (262144) + +struct cache { + struct entry entry[CACHE_LENGTH]; + volatile int length; +}; + +static void sift_up(struct entry * e, int ix) +{ + while (ix > 0) { + int parent = (ix - 1) / 2; + if (e[parent].depth < e[ix].depth || e[parent].n < e[ix].n) { + // swap parent and ix + struct entry tmp = e[parent]; + e[parent] = e[ix]; + e[ix] = tmp; + ix = parent; + } else { + return; + } + } +} + +static int search(struct entry * e, int length, int ix, int64_t n, int32_t depth) +{ + if (e[ix].depth == depth && e[ix].n == n) { + /* + uint32_t r15; + asm volatile ("mov r15,%0" + : "=r" (r15)); + if (r15 < min) { + //printf("%08x\n", r15); + min = r15; + } + */ + + return ix; + } + + int child_l = 2 * ix + 1; + int child_r = 2 * ix + 2; + + if (child_r < length && (e[child_r].depth >= depth || e[child_r].n >= n)) { + int i = search(e, length, child_r, n, depth); + if (i >= 0) + return i; + } + + if (child_l < length && (e[child_l].depth >= depth || e[child_l].n >= n)) { + int i = search(e, length, child_l, n, depth); + if (i >= 0) + return i; + } + + return -1; +} + +static void cache_add(struct cache * cache, int64_t n, int32_t depth, int64_t value) +{ + if (cache->length >= CACHE_LENGTH) + return; + + int ix = cache->length; + cache->entry[ix].n = n; + cache->entry[ix].depth = depth; + cache->entry[ix].value = value; + sift_up(cache->entry, ix); + cache->length += 1; +} + +static int64_t simulate_step(int64_t n, int depth, int max_depth, struct cache * cache) +{ + if (depth == max_depth) + return 1; + + int cache_ix = search(cache->entry, cache->length, 0, n, depth); + if (cache_ix >= 0) { + //printf("hit ix:%l %d %l\n", n, depth, cache->entry[cache_ix].value); + return cache->entry[cache_ix].value; + } + + int64_t a[2]; + int new_stones = stone_rule(n, &a[0], &a[1]); + int64_t sum = 0; + for (int i = 0; i < new_stones; i++) { + sum += simulate_step(a[i], depth + 1, max_depth, cache); + } + + //printf("store: %l %d %l\n", n, depth, sum); + cache_add(cache, n, depth, sum); + return sum; +} + +static int parse_input(const char * input, int length, + int64_t * stones) +{ + const char * end = input + length; + + int i = 0; + while (input < end) { + input = parse_base10_64(input, &stones[i]); + input = parse_skip(input, ' '); + input = parse_skip(input, '\n'); + i += 1; + } + return i; +} + +static int64_t solve(const char * input, int length, int max_depth) +{ + static struct cache cache; + int64_t stones[20]; + + int count = parse_input(input, length, stones); + + int64_t sum = 0; + for (int i = 0; i < count; i++) { + cache.length = 0; + sum += simulate_step(stones[i], 0, max_depth, &cache); + } + + return sum; +} + +int64_t day11_part1(const char * input, int length) +{ + return solve(input, length, 25); +} + +int64_t day11_part2(const char * input, int length) +{ + return solve(input, length, 75); +} diff --git a/input_dreamcast.inc b/input_dreamcast.inc index 60d3f72..8cd0f57 100644 --- a/input_dreamcast.inc +++ b/input_dreamcast.inc @@ -19,6 +19,8 @@ #include "day9/input.txt.h" #include "day10/sample1.txt.h" #include "day10/input.txt.h" +#include "day11/sample1.txt.h" +#include "day11/input.txt.h" static struct start_size sample[][2] = { { @@ -81,6 +83,12 @@ static struct start_size sample[][2] = { { ( char *)&_binary_day10_sample1_txt_start, (uint32_t)&_binary_day10_sample1_txt_size }, }, + { + { ( char *)&_binary_day11_sample1_txt_start, + (uint32_t)&_binary_day11_sample1_txt_size }, + { ( char *)&_binary_day11_sample1_txt_start, + (uint32_t)&_binary_day11_sample1_txt_size }, + }, }; static struct start_size input[] = { @@ -104,4 +112,6 @@ static struct start_size input[] = { (uint32_t)&_binary_day9_input_txt_size }, { ( char *)&_binary_day10_input_txt_start, (uint32_t)&_binary_day10_input_txt_size }, + { ( char *)&_binary_day11_input_txt_start, + (uint32_t)&_binary_day11_input_txt_size }, }; diff --git a/runner.c b/runner.c index 70529e5..986c790 100644 --- a/runner.c +++ b/runner.c @@ -32,7 +32,7 @@ bool runner_tick(struct runner_state * runner_state) int part = tick % 2; int day = tick / 2; - if (day < 9) + if (day < 10) return true; runner_state->want_render = solution[day].render != NULL; diff --git a/runner.inc b/runner.inc index 7af3b94..eafb2b2 100644 --- a/runner.inc +++ b/runner.inc @@ -21,6 +21,8 @@ int64_t day9_part1(const char * input, int length); int64_t day9_part2(const char * input, int length); int64_t day10_part1(const char * input, int length); int64_t day10_part2(const char * input, int length); +int64_t day11_part1(const char * input, int length); +int64_t day11_part2(const char * input, int length); struct day_funcs solution[] = { { @@ -63,4 +65,8 @@ struct day_funcs solution[] = { {day10_part1, day10_part2}, NULL, }, + { + {day11_part1, day11_part2}, + NULL, + }, }; diff --git a/solutions.mk b/solutions.mk index f388687..859b6a3 100644 --- a/solutions.mk +++ b/solutions.mk @@ -30,4 +30,7 @@ DAY_OBJ = \ day9/solution.o \ day10/sample1.txt.o \ day10/input.txt.o \ - day10/solution.o + day10/solution.o \ + day11/sample1.txt.o \ + day11/input.txt.o \ + day11/solution.o