diff --git a/2022/20.cpp b/2022/20.cpp new file mode 100644 index 0000000..a40c0fa --- /dev/null +++ b/2022/20.cpp @@ -0,0 +1,115 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +namespace { + +using Input = std::vector; + +/// @brief Parse the input stream as a newline-delimited list of lists of integers +/// @param in input file parsed until EOF +/// @return outer list of elves, inner lists of calories +auto Parse(std::istream & in) -> Input +{ + Input result; + using It = std::istream_iterator; + std::copy(in, {}, std::back_inserter(result)); + return result; +} + +auto Solve(Input const& input, std::size_t const rounds) -> std::int64_t +{ + std::size_t const len = input.size(); + std::vector fwds(len), bwds(len); + + for (std::size_t i = 0; i < len; ++i) { + fwds[i] = aocpp::Mod(i+1, len); + bwds[i] = aocpp::Mod(i-1, len); + } + + for (std::size_t r = 0; r < rounds; ++r) { + for (std::size_t i = 0; i < len; ++i) { + + // Remove i from the ring + auto next = fwds[i]; + auto prev = bwds[i]; + fwds[prev] = next; + bwds[next] = prev; + + auto const steps = aocpp::Mod(input[i], len - 1); + if (steps < len/2) { + for (std::size_t s = 0; s < steps; ++s) { + next = fwds[next]; + } + } else { + for (std::size_t s = 0; s < len - 1 - steps; ++s) { + next = bwds[next]; + } + } + prev = bwds[next]; + + // insert i into the ring + fwds[i] = next; + bwds[i] = prev; + fwds[prev] = i; + bwds[next] = i; + } + } + + std::int64_t sum {0}; + auto cursor = std::distance(input.begin(), std::find(input.begin(), input.end(), 0)); + for (std::size_t r = 0; r < 3; ++r) { + for (std::size_t s = 0; s < 1000; ++s) { + cursor = fwds[cursor]; + } + sum += input[cursor]; + } + + return sum; +} + +auto Part1(Input const& input) -> std::int64_t +{ + return Solve(input, 1); +} + +auto Part2(Input input) -> std::int64_t +{ + for (auto& x : input) { x *= 811589153; } + return Solve(input, 10); +} + +} // namespace + +TEST_SUITE("2022-20 examples") { + TEST_CASE("example") { + std::istringstream in { + "1\n" + "2\n" + "-3\n" + "3\n" + "-2\n" + "0\n" + "4\n"}; + auto input = Parse(in); + CHECK(3 == Part1(input)); + CHECK(1623178306 == Part2(input)); + } +} + +auto main(int argc, char** argv) -> int { + auto input = Parse(*aocpp::Startup(argc, argv)); + std::cout << "Part 1: " << Part1(input) << std::endl; + std::cout << "Part 2: " << Part2(input) << std::endl; +} diff --git a/2022/25.cpp b/2022/25.cpp index 1f6db08..f508a19 100644 --- a/2022/25.cpp +++ b/2022/25.cpp @@ -9,25 +9,14 @@ #include +#include #include namespace { +using aocpp::DivMod; using It = std::istream_iterator; -// -template -auto DivMod(T dividend, T divisor) -> std::pair -{ - auto const quotient = dividend / divisor; - auto const remainder = dividend % divisor; - if (remainder == 0 || (remainder > 0) == (divisor > 0)) { - return {quotient, remainder}; - } else { - return {quotient - 1, remainder + divisor}; - } -} - template auto FromInt(T x) -> std::string { @@ -96,18 +85,6 @@ TEST_SUITE("2022-25 examples") { 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)); - - CHECK(DivMod(-5,-5) == std::make_pair(1,0)); - CHECK(DivMod(-5,5) == std::make_pair(-1,0)); - CHECK(DivMod(5,-5) == std::make_pair(-1,0)); - CHECK(DivMod(-5,-5) == std::make_pair(1,0)); - } } auto main(int argc, char** argv) -> int diff --git a/2022/CMakeLists.txt b/2022/CMakeLists.txt index 9e8cbb9..0857755 100644 --- a/2022/CMakeLists.txt +++ b/2022/CMakeLists.txt @@ -13,5 +13,8 @@ target_link_libraries(2022_12 aocpp) add_executable(2022_18 18.cpp) target_link_libraries(2022_18 aocpp) +add_executable(2022_20 20.cpp) +target_link_libraries(2022_20 aocpp) + add_executable(2022_25 25.cpp) target_link_libraries(2022_25 aocpp) diff --git a/lib/include/aocpp/DivMod.hpp b/lib/include/aocpp/DivMod.hpp new file mode 100644 index 0000000..d7e58bf --- /dev/null +++ b/lib/include/aocpp/DivMod.hpp @@ -0,0 +1,50 @@ +#ifndef AOCPP_DIVMOD_HPP_ +#define AOCPP_DIVMOD_HPP_ + +#include + +#include "../doctest.h" + +namespace aocpp { + +template +auto DivMod(T dividend, T divisor) -> std::pair +{ + auto const quotient = dividend / divisor; + auto const remainder = dividend % divisor; + if (remainder == 0 || (remainder > 0) == (divisor > 0)) { + return {quotient, remainder}; + } else { + return {quotient - 1, remainder + divisor}; + } +} + +template +auto Mod(T dividend, T divisor) -> T +{ + return DivMod(dividend, divisor).second; +} + +template +auto Div(T dividend, T divisor) -> T +{ + return DivMod(dividend, divisor).first; +} + +TEST_SUITE("divmod.hpp") { + 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)); + + CHECK(DivMod(-5,-5) == std::make_pair(1,0)); + CHECK(DivMod(-5,5) == std::make_pair(-1,0)); + CHECK(DivMod(5,-5) == std::make_pair(-1,0)); + CHECK(DivMod(-5,-5) == std::make_pair(1,0)); + } +} + +} + +#endif