day 11
This commit is contained in:
parent
56a7b1418f
commit
b461a7d737
|
|
@ -0,0 +1 @@
|
|||
3935565 31753 437818 7697 5 38 0 123
|
||||
|
|
@ -0,0 +1,164 @@
|
|||
#include "aoc.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
static inline bool
|
||||
is_even(i64 x) { return (x & 1) == 0; }
|
||||
|
||||
static inline i64
|
||||
count_digits(i64 x) {
|
||||
ASSERT(x >= 0);
|
||||
if (x < 10ull) return 1;
|
||||
if (x < 100ull) return 2;
|
||||
if (x < 1000ull) return 3;
|
||||
if (x < 10000ull) return 4;
|
||||
if (x < 100000ull) return 5;
|
||||
if (x < 1000000ull) return 6;
|
||||
if (x < 10000000ull) return 7;
|
||||
if (x < 100000000ull) return 8;
|
||||
if (x < 1000000000ull) return 9;
|
||||
if (x < 10000000000ull) return 10;
|
||||
if (x < 100000000000ull) return 11;
|
||||
if (x < 1000000000000ull) return 12;
|
||||
if (x < 10000000000000ull) return 13;
|
||||
if (x < 100000000000000ull) return 14;
|
||||
if (x < 1000000000000000ull) return 15;
|
||||
if (x < 10000000000000000ull) return 16;
|
||||
if (x < 100000000000000000ull) return 17;
|
||||
if (x < 1000000000000000000ull) return 18;
|
||||
if (x < 10000000000000000000ull) return 19;
|
||||
return 20;
|
||||
}
|
||||
|
||||
static const i64
|
||||
POWERS_OF_TEN[] = {
|
||||
1ull,
|
||||
10ull,
|
||||
100ull,
|
||||
1000ull,
|
||||
10000ull,
|
||||
100000ull,
|
||||
1000000ull,
|
||||
10000000ull,
|
||||
100000000ull,
|
||||
1000000000ull,
|
||||
10000000000ull,
|
||||
100000000000ull,
|
||||
1000000000000ull,
|
||||
10000000000000ull,
|
||||
100000000000000ull,
|
||||
1000000000000000ull,
|
||||
10000000000000000ull,
|
||||
100000000000000000ull,
|
||||
1000000000000000000ull,
|
||||
10000000000000000000ull,
|
||||
};
|
||||
|
||||
static u64
|
||||
hash_stone_iterations(i64 stone, i32 iterations) {
|
||||
return ((u64) stone * 73856093ull) ^ ((u64) iterations * 2654435761ull);
|
||||
}
|
||||
|
||||
#define CACHE_SIZE (1 << 18) // empirically determined
|
||||
_Static_assert((CACHE_SIZE & (CACHE_SIZE - 1)) == 0, "CACHE_SIZE must be a power of 2");
|
||||
#define CACHE_MASK (CACHE_SIZE - 1)
|
||||
|
||||
typedef struct CacheSlot {
|
||||
struct CacheSlot *next;
|
||||
i64 stone;
|
||||
i32 iterations;
|
||||
i64 result;
|
||||
} CacheSlot;
|
||||
|
||||
|
||||
typedef struct Cache {
|
||||
CacheSlot *slots[CACHE_SIZE];
|
||||
Arena *arena;
|
||||
} Cache;
|
||||
|
||||
static void
|
||||
cache_init(Cache *cache, Arena *arena) {
|
||||
cache->arena = arena;
|
||||
}
|
||||
|
||||
static bool
|
||||
cache_get(Cache *cache, i64 stone, i32 iterations, i64 *result) {
|
||||
u64 hash = hash_stone_iterations(stone, iterations);
|
||||
u64 index = hash & CACHE_MASK;
|
||||
for (CacheSlot *slot = cache->slots[index]; slot; slot = slot->next) {
|
||||
if (slot->stone == stone && slot->iterations == iterations) {
|
||||
*result = slot->result;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
cache_put(Cache *cache, i64 stone, i32 iterations, i64 result) {
|
||||
u64 hash = hash_stone_iterations(stone, iterations);
|
||||
u64 index = hash & CACHE_MASK;
|
||||
for (CacheSlot *slot = cache->slots[index]; slot; slot = slot->next) {
|
||||
if (slot->stone == stone && slot->iterations == iterations) {
|
||||
slot->result = result;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// not found
|
||||
CacheSlot *slot = ARENA_ALLOC(cache->arena, CacheSlot);
|
||||
slot->stone = stone;
|
||||
slot->iterations = iterations;
|
||||
slot->result = result;
|
||||
slot->next = cache->slots[index];
|
||||
cache->slots[index] = slot;
|
||||
}
|
||||
|
||||
static i64
|
||||
evolve(Cache *cache, i64 stone, i32 iterations) {
|
||||
if (iterations == 0) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
i64 result = 0;
|
||||
if (cache_get(cache, stone, iterations, &result)) {
|
||||
return result;
|
||||
}
|
||||
else if (stone == 0) {
|
||||
result = evolve(cache, 1, iterations - 1);
|
||||
}
|
||||
else {
|
||||
i64 digit_count = count_digits(stone);
|
||||
if (is_even(digit_count)) {
|
||||
i64 pot = POWERS_OF_TEN[digit_count / 2];
|
||||
i64 left = stone / pot;
|
||||
i64 right = stone % pot;
|
||||
result = evolve(cache, left, iterations - 1) + evolve(cache, right, iterations - 1);
|
||||
}
|
||||
else {
|
||||
i64 new_stone = stone * 2024;
|
||||
result = evolve(cache, new_stone, iterations - 1);
|
||||
}
|
||||
}
|
||||
cache_put(cache, stone, iterations, result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
Arena *arena = make_arena(Megabytes(16));
|
||||
str input = str_trim(read_file(arena, argv[1]));
|
||||
|
||||
Cache *cache = ARENA_ALLOC(arena, Cache);
|
||||
cache_init(cache, arena);
|
||||
|
||||
str iter = input;
|
||||
str token;
|
||||
i64 part_1 = 0;
|
||||
i64 part_2 = 0;
|
||||
while ((token = str_next_token(&iter, STR(" "))).len > 0) {
|
||||
i64 stone = parse_i64(token, *arena);
|
||||
part_1 += evolve(cache, stone, 25);
|
||||
part_2 += evolve(cache, stone, 75);
|
||||
}
|
||||
printf("%ld\n", part_1);
|
||||
printf("%ld\n", part_2);
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
0 1 10 99 999
|
||||
|
|
@ -0,0 +1 @@
|
|||
125 17
|
||||
Loading…
Reference in New Issue