From f928437f9cfc6699d651ddd55688db7851c2a4ea Mon Sep 17 00:00:00 2001 From: Matthew Gretton-Dann Date: Tue, 5 Dec 2023 09:47:19 +0000 Subject: [PATCH] 2023 Day 5 --- 2023/puzzle-05-01.cc | 102 +++++++++++++++++++++++++++++ 2023/puzzle-05-02.cc | 150 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 252 insertions(+) create mode 100644 2023/puzzle-05-01.cc create mode 100644 2023/puzzle-05-02.cc diff --git a/2023/puzzle-05-01.cc b/2023/puzzle-05-01.cc new file mode 100644 index 0000000..a97ab8e --- /dev/null +++ b/2023/puzzle-05-01.cc @@ -0,0 +1,102 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using UInt = std::uint64_t; +using NumVec = std::vector; + +auto operator<<(std::ostream& os, NumVec const& vec) -> std::ostream& +{ + for (auto const num : vec) { os << ' ' << num; } + return os; +} + +template +void read_nums(It it, std::string_view const nums) +{ + char const* pos{nums.data()}; + while (pos - nums.data() < nums.size()) { + char* next_pos{nullptr}; + *it++ = std::strtoull(pos, &next_pos, 10); + pos = next_pos; + } +} + +struct MapEntry +{ + explicit MapEntry(NumVec const& vec) + : dest_(vec[0]), source_(vec[1]), length_(vec[2]) + { + assert(vec.size() == 3); + } + + UInt dest_; + UInt source_; + UInt length_; +}; + +struct ThingyMap +{ + void add(std::string_view line) + { + NumVec vec; + read_nums(std::back_inserter(vec), line); + assert(vec.size() == 3); + entries_.emplace_back(vec); + } + + [[nodiscard]] auto transform(UInt const in) const -> UInt + { + for (auto const [dest, source, length] : entries_) { + if (in < source) { continue; } + if (in >= source + length) { continue; } + return dest + (in - source); + } + return in; + } + + std::vector entries_; +}; + +auto main() -> int try { + std::string line; + NumVec seeds{}; + std::getline(std::cin, line); + + // Read the seeds. + assert(line.substr(0, 6) == "seeds:"); + read_nums(std::back_inserter(seeds), line.substr(6)); + std::cout << "Seeds:" << seeds << '\n'; + + // Skip whitespace + std::getline(std::cin, line); + + while (std::getline(std::cin, line)) { + std::cout << line << ":"; + ThingyMap map; + while (std::getline(std::cin, line)) { + if (line.empty()) { break; } + map.add(line); + } + NumVec transformed; + + std::transform(seeds.begin(), seeds.end(), std::back_inserter(transformed), + [&map](UInt in) { return map.transform(in); }); + std::cout << transformed << '\n'; + seeds = transformed; + } + + std::cout << "Minimum: " << *std::ranges::min_element(seeds.begin(), seeds.end()) << '\n';; + + return EXIT_SUCCESS; +} +catch (...) { + std::cerr << "Uncaught exception.\n"; + return EXIT_FAILURE; +} diff --git a/2023/puzzle-05-02.cc b/2023/puzzle-05-02.cc new file mode 100644 index 0000000..6d6d2a8 --- /dev/null +++ b/2023/puzzle-05-02.cc @@ -0,0 +1,150 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using UInt = std::uint64_t; +using NumVec = std::vector; +using Range = std::pair; +using RangeVec = std::vector; + +auto operator<<(std::ostream& os, RangeVec const& ranges) -> std::ostream& +{ + for (auto [start, length] : ranges) { + os << " [" << start << '+' << length << ']'; + } + return os; +} + +template +void read_nums(It it, std::string_view const nums) +{ + char const* pos{nums.data()}; + while (pos - nums.data() < nums.size()) { + char* next_pos{nullptr}; + *it++ = std::strtoull(pos, &next_pos, 10); + pos = next_pos; + } +} + +template +void read_ranges(It it, std::string_view const nums) +{ + char const* pos{nums.data()}; + while (pos - nums.data() < nums.size()) { + char* next_pos{nullptr}; + auto start = std::strtoull(pos, &next_pos, 10); + pos = next_pos; + auto length = std::strtoull(pos, &next_pos, 10); + pos = next_pos; + *it++ = std::make_pair(start, length); + } +} + +struct MapEntry +{ + explicit MapEntry(NumVec const& vec) + : dest_(vec[0]), source_(vec[1]), length_(vec[2]) + { + assert(vec.size() == 3); + } + + UInt dest_; + UInt source_; + UInt length_; +}; + +struct ThingyMap +{ + void add(std::string_view const line) + { + NumVec vec; + read_nums(std::back_inserter(vec), line); + assert(vec.size() == 3); + entries_.emplace_back(vec); + } + + template + void transform(It it, UInt const range_start, UInt const range_length) const + { + /* Look for a start range that starts inside a map entry. */ + for (auto const [dest, source, length] : entries_) { + if (range_start < source) { continue; } + if (range_start >= source + length) { continue; } + auto const offset = range_start - source; + auto const new_length = std::min(range_length, length - offset); + assert(new_length != 0); + *it++ = std::make_pair(dest + offset, new_length); + if (new_length != range_length) { + transform(it, range_start + new_length, range_length - new_length); + } + return; + } + + /* Now look for an end that ends inside a map entry. */ + for (auto const [dest, source, length] : entries_) { + auto const range_end = range_start + range_length; + if (range_end <= source) { continue; } + if (range_end > source + length) { continue; } + assert(source > range_start); + auto const new_length = source - range_start; + assert(new_length != 0); + *it++ = std::make_pair(range_start, new_length); + if (range_length != new_length) { + transform(it, range_start + new_length, range_length - new_length); + } + return; + } + + *it++ = std::make_pair(range_start, range_length); + } + + std::vector entries_; +}; + +auto main() -> int try { + std::string line; + RangeVec seeds{}; + std::getline(std::cin, line); + + // Read the seeds. + assert(line.substr(0, 6) == "seeds:"); + read_ranges(std::back_inserter(seeds), line.substr(6)); + std::cout << "Seeds:" << seeds << '\n'; + + // Skip whitespace + std::getline(std::cin, line); + + while (std::getline(std::cin, line)) { + std::cout << line << ":"; + ThingyMap map; + while (std::getline(std::cin, line)) { + if (line.empty()) { break; } + map.add(line); + } + RangeVec transformed; + + for (auto [start, length] : seeds) { + map.transform(std::back_inserter(transformed), start, length); + } + std::cout << transformed << '\n'; + seeds = transformed; + } + + std::cout << "Minimum: " << std::ranges::min_element(seeds.begin(), seeds.end(), + [](Range const& left, Range const& right) { + return left.first < right.first; + })->first << '\n'; + + return EXIT_SUCCESS; +} +catch (...) { + std::cerr << "Uncaught exception.\n"; + return EXIT_FAILURE; +}