AOC2023: implement day5

This commit is contained in:
Bananymous 2023-12-05 09:13:13 +02:00
parent 95fc894303
commit 82cb2ea20b
3 changed files with 212 additions and 0 deletions

View File

@ -7,6 +7,7 @@ set(AOC2023_PROJECTS
day2
day3
day4
day5
)
set(BANAN_AOC2023_BIN ${BANAN_BIN}/aoc2023)

View File

@ -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)

View File

@ -0,0 +1,189 @@
#include <BAN/HashMap.h>
#include <BAN/Vector.h>
#include <stdio.h>
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<Value> 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<ValueRange> 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);
}