diff --git a/userspace/aoc2024/CMakeLists.txt b/userspace/aoc2024/CMakeLists.txt index 5e608ad2..ebb7312d 100644 --- a/userspace/aoc2024/CMakeLists.txt +++ b/userspace/aoc2024/CMakeLists.txt @@ -9,6 +9,7 @@ set(AOC2024_PROJECTS day8 day9 day10 + day11 full ) diff --git a/userspace/aoc2024/day11/CMakeLists.txt b/userspace/aoc2024/day11/CMakeLists.txt new file mode 100644 index 00000000..f8d29c03 --- /dev/null +++ b/userspace/aoc2024/day11/CMakeLists.txt @@ -0,0 +1,9 @@ +set(SOURCES + main.cpp +) + +add_executable(aoc2024_day11 ${SOURCES}) +banan_include_headers(aoc2024_day11 ban) +banan_link_library(aoc2024_day11 libc) + +install(TARGETS aoc2024_day11 OPTIONAL) diff --git a/userspace/aoc2024/day11/main.cpp b/userspace/aoc2024/day11/main.cpp new file mode 100644 index 00000000..da54b461 --- /dev/null +++ b/userspace/aoc2024/day11/main.cpp @@ -0,0 +1,120 @@ +#include +#include +#include + +#include +#include + +using i8 = int8_t; +using i16 = int16_t; +using i32 = int32_t; +using i64 = int64_t; + +using u8 = uint8_t; +using u16 = uint16_t; +using u32 = uint32_t; +using u64 = uint64_t; + +u64 even_divisor(u64 stone) +{ + u8 digits = 0; + for (u64 mult = 1; mult <= stone; mult *= 10) + digits++; + + if (digits % 2) + return 0; + + u64 divisor = 1; + for (u8 i = 0; i < digits / 2; i++) + divisor *= 10; + + return divisor; +} + +u64 count_stones(u64 stone, u8 depth) +{ + static BAN::HashMap cache; + + if (depth == 0) + return 1; + + const u64 cache_key = (stone << 8) | depth; + + auto it = cache.find(cache_key); + if (it != cache.end()) + return it->value; + + if (stone == 0) + return count_stones(1, depth - 1); + + u64 divisor = even_divisor(stone); + if (divisor == 0) + return count_stones(stone * 2024, depth - 1); + + u64 result = 0; + result += count_stones(stone / divisor, depth - 1); + result += count_stones(stone % divisor, depth - 1); + MUST(cache.insert(cache_key, result)); + return result; +} + +i64 part1(FILE* fp) +{ + BAN::Vector stones; + + char buffer[128]; + ASSERT (fgets(buffer, sizeof(buffer), fp)); + { + auto strs = MUST(BAN::StringView(buffer).split(' ')); + for (auto str : strs) + MUST(stones.push_back(atoll(str.data()))); + } + + u64 result = 0; + for (size_t i = 0; i < stones.size(); i++) + result += count_stones(stones[i], 25); + + return result; +} + +i64 part2(FILE* fp) +{ + BAN::Vector stones; + + char buffer[128]; + ASSERT (fgets(buffer, sizeof(buffer), fp)); + { + auto strs = MUST(BAN::StringView(buffer).split(' ')); + for (auto str : strs) + MUST(stones.push_back(atoll(str.data()))); + } + + u64 result = 0; + for (size_t i = 0; i < stones.size(); i++) + result += count_stones(stones[i], 75); + + return result; +} + +int main(int argc, char** argv) +{ + const char* file_path = "/usr/share/aoc2024/day11_input.txt"; + + if (argc >= 2) + file_path = argv[1]; + + FILE* fp = fopen(file_path, "r"); + if (fp == nullptr) + { + perror("fopen"); + return 1; + } + + printf("part1: %" PRId64 "\n", part1(fp)); + + fseek(fp, 0, SEEK_SET); + + printf("part2: %" PRId64 "\n", part2(fp)); + + fclose(fp); +}