#include #include #include #include #include #include #include #include #include #include #include using aocpp::Coord; using aocpp::Grid; namespace { auto Parse(std::istream & in) -> std::tuple, Coord, Grid> { std::tuple, Coord, Grid> result {{},{},{},Grid::Parse(in)}; // I'd use a structured binding here, but not all current compilers // supports capture of the resulting bindings in the lambda below auto& start1 = std::get<0>(result); auto& starts2 = std::get<1>(result); auto& end = std::get<2>(result); auto& grid = std::get<3>(result); grid.each([&](Coord c, char v) { switch (v) { case 'S': grid[c] = 'a'; start1 = c; break; case 'E': grid[c] = 'z'; end = c; break; case 'a': starts2.push_back(c); break; } }); return result; } auto Solve(std::vector starts, Coord end, Grid const& grid) -> std::optional { std::vector next_layer; std::set seen; std::int64_t counter {}; while (!starts.empty()) { counter++; for (auto const& here : starts) { if (!seen.insert(here).second) continue; for (auto const next : {Up(here), Down(here), Left(here), Right(here)}) { if (grid.contains(next) && grid[next] <= grid[here] + 1) { if (next == end) { return counter; } next_layer.push_back(next); } } } std::swap(starts, next_layer); next_layer.clear(); } return {}; } } // namespace TEST_SUITE("2022-12 examples") { TEST_CASE("documented example") { std::istringstream in { "Sabqponm\n" "abcryxxl\n" "accszExk\n" "acctuvwj\n" "abdefghi\n" }; auto [start1, starts2, end, grid] = Parse(in); CHECK(31 == Solve({start1}, end, grid)); CHECK(29 == Solve(std::move(starts2), end, grid)); } } auto Main(std::istream & in, std::ostream & out) -> void { auto [start1, starts2, end, grid] = Parse(in); out << "Part 1: " << Solve({start1}, end, grid).value_or(-1) << std::endl; out << "Part 2: " << Solve(std::move(starts2), end, grid).value_or(-1) << std::endl; }