diff --git a/2022/14.cpp b/2022/14.cpp index 154f6da..bca1afd 100644 --- a/2022/14.cpp +++ b/2022/14.cpp @@ -1,9 +1,20 @@ +#include + #include #include #include #include +#include #include +#if __has_include() +#include +namespace co = std; +#elif __has_include() +#include +namespace co = std::experimental; +#endif + #include #include #include @@ -92,23 +103,59 @@ auto FindBottom(Input const& input) -> std::int64_t return result; } +struct CoordPromise; + +struct CoordGenerator : co::coroutine_handle { + using promise_type = struct CoordPromise; + auto next() -> std::optional; +}; + +struct CoordPromise { + std::optional output; + std::exception_ptr e; + + auto get_return_object() -> CoordGenerator { return { CoordGenerator::from_promise(*this)}; } + auto initial_suspend() noexcept -> co::suspend_always { return {}; } + auto final_suspend() noexcept -> co::suspend_never { return {}; } + auto return_void() { output.reset(); } + auto yield_value(aocpp::Coord coord) -> co::suspend_always { output = coord; return {}; } + auto unhandled_exception() -> void { e = std::current_exception(); } +}; + +auto CoordGenerator::next() -> std::optional { + resume(); + auto & p = promise(); + if (p.e) { + std::rethrow_exception(p.e); + } + return p.output; +} + +auto SearchOrder(std::set & world, aocpp::Coord here) -> CoordGenerator +{ + co_yield aocpp::Down(here); + co_yield aocpp::Left(aocpp::Down(here)); + co_yield aocpp::Right(aocpp::Down(here)); + world.insert(here); +} + auto Part1(std::int64_t bottom, std::set world) -> std::size_t { - auto path = std::vector{TOP}; auto const starting_size = world.size(); + auto path = std::vector{}; + path.reserve(bottom - TOP.y); + path.push_back(SearchOrder(world, TOP)); + while (!path.empty()) { - auto & here = path.back(); - if (here.y == bottom) { - return world.size() - starting_size; - } else if (!world.contains(aocpp::Down(here))) { - path.push_back(aocpp::Down(here)); - } else if (!world.contains(aocpp::Left(aocpp::Down(here)))) { - path.push_back(aocpp::Left(aocpp::Down(here))); - } else if (!world.contains(aocpp::Right(aocpp::Down(here)))) { - path.push_back(aocpp::Right(aocpp::Down(here))); + if (auto next = path.back().next()) { + if (!world.contains(*next)) { + if (next->y == bottom) { + break; + } + path.push_back(SearchOrder(world, *next)); + } } else { - world.insert(here); path.pop_back(); } } @@ -118,22 +165,18 @@ auto Part1(std::int64_t bottom, std::set world) -> std::size_t auto Part2(std::int64_t bottom, std::set world) -> std::size_t { - auto path = std::vector{TOP}; auto const starting_size = world.size(); + + auto path = std::vector{}; + path.reserve(2 + bottom - TOP.y); + path.push_back(SearchOrder(world, TOP)); while (!path.empty()) { - auto & here = path.back(); - if (here.y == 1 + bottom) { - world.insert(here); - path.pop_back(); - } else if (!world.contains(aocpp::Down(here))) { - path.push_back(aocpp::Down(here)); - } else if (!world.contains(aocpp::Left(aocpp::Down(here)))) { - path.push_back(aocpp::Left(aocpp::Down(here))); - } else if (!world.contains(aocpp::Right(aocpp::Down(here)))) { - path.push_back(aocpp::Right(aocpp::Down(here))); + if (auto next = path.back().next()) { + if (next->y - 2 != bottom && !world.contains(*next)) { + path.push_back(SearchOrder(world, *next)); + } } else { - world.insert(here); path.pop_back(); } }