From 978a8ad39deac9eb04903e2cde7e46567f1bf3b0 Mon Sep 17 00:00:00 2001 From: Eric Mertens Date: Fri, 13 Jan 2023 16:21:25 -0800 Subject: [PATCH] 2022-25 --- 2022/25.cpp | 110 ++++++++++++++++++++++++++++++++++++++++++++ 2022/CMakeLists.txt | 3 ++ 2 files changed, 113 insertions(+) create mode 100644 2022/25.cpp diff --git a/2022/25.cpp b/2022/25.cpp new file mode 100644 index 0000000..633b450 --- /dev/null +++ b/2022/25.cpp @@ -0,0 +1,110 @@ +#include // int64_t +#include // plus +#include // istream +#include // istream_iterator +#include // transform_reduce +#include // istringstream +#include // string +#include // pair, make_pair + +#include + +#include + +namespace { + +// +template +auto DivMod(T dividend, T divisor) -> std::pair +{ + auto const quotient = dividend / divisor; + auto const remainder = dividend % divisor; + if ((remainder >= 0) == (divisor >= 0)) { + return {quotient, remainder}; + } else { + return {quotient - 1, remainder + divisor}; + } +} + +template +auto FromInt(T x) -> std::string +{ + std::string output; + char const digits[] {"=-012"}; + while (x != 0) { + auto [x_, i] = DivMod(x + 2, 5); // plain % and / are insufficient for negatives + x = x_; + output.push_back(digits[i]); + } + std::reverse(output.begin(), output.end()); + return output; +} + +template +auto ToInt(std::string const& str) -> T +{ + T acc {0}; + for (char c : str) { + acc *= 5; + switch (c) { + case '2': acc += 2; break; + case '1': acc += 1; break; + case '0': break; + case '-': acc -= 1; break; + case '=': acc -= 2; break; + } + } + return acc; +} + +auto Solve(std::istream & in) -> std::string +{ + using It = std::istream_iterator; + return FromInt(std::transform_reduce(It(in), It(), 0, std::plus(), ToInt)); +} + +} // namespace + +TEST_SUITE("2022-25 examples") { + TEST_CASE("example") { + std::istringstream in { + "1=-0-2\n" + "12111\n" + "2=0=\n" + "21\n" + "2=01\n" + "111\n" + "20012\n" + "112\n" + "1=-1=\n" + "1-12\n" + "12\n" + "1=\n" + "122\n" + }; + CHECK(Solve(in) == "2=-1=0"); + } + // The example input doesn't test out any negative numbers + TEST_CASE("Negative numbers") { + CHECK(ToInt("-") == -1); + CHECK(ToInt("=") == -2); + CHECK(ToInt("-=") == -7); + CHECK(ToInt("=-") == -11); + CHECK(FromInt(-1) == "-"); + CHECK(FromInt(-2) == "="); + CHECK(FromInt(-7) == "-="); + CHECK(FromInt(-11) == "=-"); + } + + TEST_CASE("DivMod behavior") { + CHECK(DivMod(2,5) == std::make_pair(0,2)); + CHECK(DivMod(-2,5) == std::make_pair(-1,3)); + CHECK(DivMod(2,-5) == std::make_pair(-1,-3)); + CHECK(DivMod(-2,-5) == std::make_pair(0,-2)); + } +} + +auto main(int argc, char** argv) -> int +{ + std::cout << "Part 1: " << Solve(*aocpp::Startup(argc, argv)) << std::endl; +} diff --git a/2022/CMakeLists.txt b/2022/CMakeLists.txt index d7366a4..a9fe453 100644 --- a/2022/CMakeLists.txt +++ b/2022/CMakeLists.txt @@ -6,3 +6,6 @@ target_link_libraries(2022_03 aocpp) add_executable(2022_04 04.cpp) target_link_libraries(2022_04 aocpp) + +add_executable(2022_25 25.cpp) +target_link_libraries(2022_25 aocpp)