diff --git a/userspace/aoc2023/CMakeLists.txt b/userspace/aoc2023/CMakeLists.txt index d21ce7beba..81b74da6c1 100644 --- a/userspace/aoc2023/CMakeLists.txt +++ b/userspace/aoc2023/CMakeLists.txt @@ -7,6 +7,7 @@ set(AOC2023_PROJECTS day2 day3 day4 + day5 ) set(BANAN_AOC2023_BIN ${BANAN_BIN}/aoc2023) diff --git a/userspace/aoc2023/day5/CMakeLists.txt b/userspace/aoc2023/day5/CMakeLists.txt new file mode 100644 index 0000000000..e9897bf7c3 --- /dev/null +++ b/userspace/aoc2023/day5/CMakeLists.txt @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 3.26) + +project(aoc2023_day5 CXX) + +set(SOURCES + main.cpp +) + +add_executable(aoc2023_day5 ${SOURCES}) +target_compile_options(aoc2023_day5 PUBLIC -O2 -g) +target_link_libraries(aoc2023_day5 PUBLIC libc ban) + +add_dependencies(aoc2023_day5 libc-install ban-install) + +add_custom_target(aoc2023_day5-install + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/aoc2023_day5 ${BANAN_AOC2023_BIN}/day5 + DEPENDS aoc2023_day5 + DEPENDS aoc2023_always +) + +add_dependencies(aoc2023 aoc2023_day5) +add_dependencies(aoc2023-install aoc2023_day5-install) diff --git a/userspace/aoc2023/day5/main.cpp b/userspace/aoc2023/day5/main.cpp new file mode 100644 index 0000000000..f819fb9ec1 --- /dev/null +++ b/userspace/aoc2023/day5/main.cpp @@ -0,0 +1,189 @@ +#include +#include + +#include + +using i64 = int64_t; + +i64 parse_i64(BAN::StringView sv) +{ + i64 value = 0; + for (char c : sv) + value = (value * 10) + (c - '0'); + return value; +} + +i64 puzzle1(FILE* fp) +{ + struct Value + { + i64 value; + i64 depth; + }; + BAN::Vector current; + + char buffer[256]; + if (!fgets(buffer, sizeof(buffer), fp)) + return -1; + + { + BAN::StringView line(buffer); + line = line.substring(0, line.size() - 1); + + auto seeds_str = MUST(line.split(' ')); + for (i64 i = 1; i < seeds_str.size(); i++) + MUST(current.emplace_back(parse_i64(seeds_str[i]), 0)); + } + + fgets(buffer, sizeof(buffer), fp); + fgets(buffer, sizeof(buffer), fp); + + i64 index = 1; + + while (fgets(buffer, sizeof(buffer), fp)) + { + if (*buffer == '\n') + { + index++; + fgets(buffer, sizeof(buffer), fp); + continue; + } + + BAN::StringView line(buffer); + line = line.substring(0, line.size() - 1); + + auto values_str = MUST(line.split(' ')); + + i64 dst = parse_i64(values_str[0]); + i64 src = parse_i64(values_str[1]); + i64 len = parse_i64(values_str[2]); + + for (Value& value : current) + { + if (value.depth < index && src <= value.value && value.value < src + len) + { + value.value += dst - src; + value.depth = index; + } + } + } + + i64 result = INT64_MAX; + for (const auto& value : current) + result = BAN::Math::min(value.value, result); + return result; +} + +i64 puzzle2(FILE* fp) +{ + struct ValueRange + { + i64 value; + i64 length; + i64 depth; + }; + BAN::Vector current; + + char buffer[256]; + if (!fgets(buffer, sizeof(buffer), fp)) + return -1; + + { + BAN::StringView line(buffer); + line = line.substring(0, line.size() - 1); + auto seeds_str = MUST(line.split(' ')); + for (i64 i = 1; i < seeds_str.size(); i += 2) + MUST(current.emplace_back(parse_i64(seeds_str[i]), parse_i64(seeds_str[i + 1]), 0)); + } + + fgets(buffer, sizeof(buffer), fp); + fgets(buffer, sizeof(buffer), fp); + + i64 index = 1; + + while (fgets(buffer, sizeof(buffer), fp)) + { + if (*buffer == '\n') + { + index++; + fgets(buffer, sizeof(buffer), fp); + continue; + } + + BAN::StringView line(buffer); + line = line.substring(0, line.size() - 1); + + auto values_str = MUST(line.split(' ')); + + i64 dst = parse_i64(values_str[0]); + i64 src = parse_i64(values_str[1]); + i64 len = parse_i64(values_str[2]); + + for (size_t i = 0; i < current.size(); i++) + { + auto& range = current[i]; + if (range.depth >= index) + continue; + + // remap whole range (src range contains full range) + if (src <= range.value && range.value + range.length <= src + len) + { + range.value += dst - src; + range.depth = index; + continue; + } + + // if current range contains any point from src range, split current range + i64 first_length = 0; + if (!first_length && range.value <= src && src < range.value + range.length) + first_length = src - range.value; + if (!first_length && range.value <= src + len - 1 && src + len - 1 < range.value + range.length) + first_length = (src + len) - range.value; + if (first_length) + { + ValueRange next_range; + next_range.value = range.value + first_length; + next_range.length = range.length - first_length; + next_range.depth = range.depth; + + range.length = first_length; + + MUST(current.insert(i + 1, next_range)); + + i--; + continue; + } + + ASSERT(src + len - 1 < range.value || src > range.value + range.length - 1); + } + } + + i64 result = INT64_MAX; + for (const auto& range : current) + if (range.length) + result = BAN::Math::min(range.value, result); + return result; +} + +int main(int argc, char** argv) +{ + const char* file_path = "/usr/share/aoc2023/day5_input.txt"; + + if (argc >= 2) + file_path = argv[1]; + + FILE* fp = fopen(file_path, "r"); + if (fp == nullptr) + { + perror("fopen"); + return 1; + } + + printf("puzzle1: %lld\n", puzzle1(fp)); + + fseek(fp, 0, SEEK_SET); + + printf("puzzle2: %lld\n", puzzle2(fp)); + + fclose(fp); +}