advent-of-code-2024/day-19/main.c

139 lines
3.7 KiB
C

#include "aoc.h"
typedef struct CacheEntry {
struct CacheEntry *next;
u64 hash;
str design;
i64 count;
} CacheEntry;
#define CACHE_SIZE (1 << 16)
_Static_assert((CACHE_SIZE & (CACHE_SIZE - 1)) == 0, "Cache size must be a power of two");
typedef struct {
Arena *arena;
CacheEntry *entries[CACHE_SIZE];
} Cache;
static void
cache_init(Cache *cache, Arena *arena) {
cache->arena = arena;
}
static u64
hash_str(str s) {
// fnv-1a hash
u64 hash = 14695981039346656037ULL;
for (i32 i = 0; i < s.len; i++) {
hash ^= s.data[i];
hash *= 1099511628211ULL;
}
return hash;
}
static f32
cache_get_load_factor(Cache *cache) {
i32 count = 0;
for (i32 i = 0; i < CACHE_SIZE; i++) {
count += (cache->entries[i] != NULL);
}
return (f32) count / CACHE_SIZE;
}
static CacheEntry *
cache_get(Cache *cache, str design) {
u64 hash = hash_str(design);
u64 index = hash & (CACHE_SIZE - 1);
for (CacheEntry *e = cache->entries[index]; e; e = e->next) {
if (e->hash == hash && str_eq(e->design, design)) {
return e;
}
}
return NULL;
}
static void
cache_put(Cache *cache, str design, i64 count) {
u64 hash = hash_str(design);
u64 index = hash & (CACHE_SIZE - 1);
for (CacheEntry *e = cache->entries[index]; e; e = e->next) {
if (e->hash == hash && str_eq(e->design, design)) {
e->count = count;
}
}
CacheEntry *entry = ARENA_ALLOC(cache->arena, CacheEntry);
entry->hash = hash;
entry->design = design;
entry->count = count;
entry->next = cache->entries[index];
cache->entries[index] = entry;
}
static i64 cache_hit_count = 0;
static i64 cache_miss_count = 0;
static i64
count_realizations(Cache *cache, str design, str *patterns, i32 len) {
if (design.len == 0) {
return 1;
}
else {
CacheEntry *entry;
i64 total = 0;
if ((entry = cache_get(cache, design))) {
cache_hit_count++;
total = entry->count;
}
else {
cache_miss_count++;
for (i32 i = 0; i < len; i++) {
if (str_starts_with(design, patterns[i])) {
str remainder = str_sub(design, patterns[i].len, design.len);
total += count_realizations(cache, remainder, patterns, len);
}
}
cache_put(cache, design, total);
}
return total;
}
}
int main(int argc, char **argv) {
Arena *arena = make_arena(Megabytes(2));
Tokens lines = read_lines(arena, argv[1]);
str avail_line = lines.tokens[0];
DYNAMIC_ARRAY(str) patterns = {0};
str pattern = {0};
while ((pattern = str_next_token(&avail_line, STR(","))).len > 0) {
*push(&patterns, arena) = str_trim(pattern);
}
Tokens desired = {
.tokens = lines.tokens + 2,
.len = lines.len - 2,
};
Cache *cache = ARENA_ALLOC(arena, Cache);
cache_init(cache, arena);
i64 part_1 = 0;
i64 part_2 = 0;
for (i32 i = 0; i < desired.len; i++) {
str towel = str_trim(desired.tokens[i]);
i64 count = count_realizations(cache, towel, patterns.data, patterns.len);
part_1 += (i64) (count > 0);
part_2 += count;
/* printf(STR_FMT " -> %s (%ld)\n", STR_ARG(towel), (count > 0) ? "possible" : "impossible", count); */
}
printf("%ld\n", part_1);
printf("%ld\n", part_2);
if (false) {
printf("Hit count: %ld\n", cache_hit_count);
printf("Miss count: %ld\n", cache_miss_count);
printf("Hit Rate: %.2f%%\n", (f64) cache_hit_count / (cache_hit_count + cache_miss_count) * 100);
printf("Load factor: %.2f%%\n", cache_get_load_factor(cache) * 100);
}
}