diff --git a/2017/22.cpp b/2017/22.cpp index 0ff538e..9abb984 100644 --- a/2017/22.cpp +++ b/2017/22.cpp @@ -17,13 +17,13 @@ auto Part1(aocpp::Grid const &input, std::int64_t reps = 10'000) -> std::int64_t std::unordered_set infected; // Initialize set of infected locations - input.each([&infected](auto const pos, auto const cell) + for (auto [pos, cell] : input) { if (cell == '#') { infected.insert(pos); } - }); + } // Start in the middle aocpp::Coord pos; @@ -62,13 +62,13 @@ auto Part2(aocpp::Grid const &input, std::int64_t reps = 10'000'000) -> std::int std::unordered_map cells; // Initialize set of infected locations - input.each([&cells](auto const pos, auto const cell) + for (auto [pos, cell] : input) { if (cell == '#') { cells.try_emplace(pos, '#'); } - }); + } // Start in the middle aocpp::Coord pos; diff --git a/2018/15.cpp b/2018/15.cpp index 80f9175..23a88fd 100644 --- a/2018/15.cpp +++ b/2018/15.cpp @@ -60,11 +60,11 @@ Game::Game(Grid grid) , debug_out_{} { // set each unit to its initial hit points - grid_.each([&](auto k, auto v) { + for (auto [k, v] : grid_) { if (IsUnit(v)) { units_[k] = initial_hp; } - }); + } } // Render the game as seen in the examples @@ -166,9 +166,9 @@ auto Game::Simulate() -> std::optional { // Detect when no targets remain for this unit and end the game auto game_over = true; - grid_.each([&](auto k, auto v) { + for (auto [k, v] : grid_) { if (IsOpposed(active_team, v)) game_over = false; - }); + } if (game_over) { int total_hp = 0; for (auto const& [_,v] : units_) { total_hp += v; } diff --git a/2019/10.cpp b/2019/10.cpp index f933c76..120ec22 100644 --- a/2019/10.cpp +++ b/2019/10.cpp @@ -70,23 +70,23 @@ auto ClearView(Grid const& grid, Coord src, Coord dst) -> bool { auto Part1(Grid const& grid) { std::size_t best = 0; Coord base {}; - grid.each([&](Coord src, char s) { + for (auto [src, s] : grid) { if ('#' == s) { std::size_t visible = 0; - grid.each([&](Coord dst, char d){ + for (auto [dst, d] : grid) { if ('#' == d && src != dst) { if (ClearView(grid, src, dst)) { visible++; } } - }); + } if (visible > best) { best = visible; base = src; } } - }); + } return std::make_pair(best, base); } @@ -94,11 +94,11 @@ auto Part2(Grid const& grid, Coord base, std::size_t n) { std::map, std::vector> targets; // arrange all the other asteroids by their angle relative to the base - grid.each([&](Coord c, char v){ + for (auto [c, v] : grid){ if (c != base && v == '#') { targets[angle(c-base)].push_back(c); } - }); + } // Sort to vectors per angle such that the nearest asteroids are at // the end of the list diff --git a/2019/17.cpp b/2019/17.cpp index 2b76050..3bd19ba 100644 --- a/2019/17.cpp +++ b/2019/17.cpp @@ -66,14 +66,14 @@ auto ComputePath(Grid const& grid) { // Determine starting location and direction Coord start{}, step{}; - grid.each([&](Coord c, char v) { + for (auto [c, v] : grid) { switch (v) { case '^': start = c; step = { 0, -1}; break; case '>': start = c; step = { 0, 1}; break; case '<': start = c; step = {-1, 0}; break; case 'v': start = c; step = { 0, 1}; break; } - }); + } auto is_path = [&](Coord c) { return grid.contains(c) && grid[c] == '#'; diff --git a/2019/18.cpp b/2019/18.cpp index 59fd2fa..9f1ebc6 100644 --- a/2019/18.cpp +++ b/2019/18.cpp @@ -41,11 +41,11 @@ auto SetKey(Doors& doors, char key) { auto FindFeatures(Grid const& grid) -> Features { Features features; - grid.each([&](Coord c, char v) { + for (auto [c, v] : grid) { if ('#' != v && '.' != v) { features[v] = c; } - }); + } return features; } diff --git a/2019/24.cpp b/2019/24.cpp index 7bd1113..6ee45b4 100644 --- a/2019/24.cpp +++ b/2019/24.cpp @@ -27,9 +27,9 @@ auto FindBugs(Grid const& grid) -> std::vector { std::int64_t w = grid.Cols(); std::int64_t h = grid.Rows(); - grid.each([&](Coord c, char v) { + for (auto [c, v] : grid) { if (v == '#') result.push_back(c); - }); + } return result; } diff --git a/2022/08.cpp b/2022/08.cpp index 7a9c116..fd0dc27 100644 --- a/2022/08.cpp +++ b/2022/08.cpp @@ -22,7 +22,7 @@ Dir directions[4] {Up, Down, Left, Right}; auto Part1(Grid const& grid) -> std::int64_t { std::int64_t result {0}; - grid.each([&](Coord const c, char const v) { + for (auto [c, v] : grid) { result += std::any_of( std::begin(directions), std::end(directions), [&](Dir const dir) { @@ -31,14 +31,14 @@ auto Part1(Grid const& grid) -> std::int64_t } return true; }); - }); + } return result; } auto Part2(Grid const& grid) -> std::int64_t { std::int64_t result {0}; - grid.each([&](Coord const c, char const v) { + for (auto [c, v] : grid) { auto score = std::transform_reduce( std::begin(directions), std::end(directions), std::int64_t{1}, std::multiplies(), // product @@ -51,7 +51,7 @@ auto Part2(Grid const& grid) -> std::int64_t return count; }); if (result < score) result = score; - }); + } return result; } diff --git a/2022/12.cpp b/2022/12.cpp index 37a0aa0..8917408 100644 --- a/2022/12.cpp +++ b/2022/12.cpp @@ -27,13 +27,13 @@ auto Parse(std::istream & in) -> std::tuple, Coord, Gr auto& end = std::get<2>(result); auto& grid = std::get<3>(result); - grid.each([&](Coord c, char v) { + for (auto [c, v] : grid) { 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; } diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index f21d974..88c0a7f 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -1,3 +1,3 @@ -add_library(aocpp src/Startup.cpp src/Coord.cpp src/Parsing.cpp) +add_library(aocpp src/Startup.cpp src/Coord.cpp src/Parsing.cpp src/Grid.cpp) target_include_directories(aocpp PUBLIC include) target_link_libraries(aocpp Boost::headers) \ No newline at end of file diff --git a/lib/include/aocpp/Grid.hpp b/lib/include/aocpp/Grid.hpp index 8d09f3f..c0af26c 100644 --- a/lib/include/aocpp/Grid.hpp +++ b/lib/include/aocpp/Grid.hpp @@ -1,7 +1,6 @@ #ifndef AOCPP_GRID_HPP_ #define AOCPP_GRID_HPP_ -#include #include #include #include @@ -12,6 +11,31 @@ namespace aocpp { +struct Grid; + +struct GridElement { + const Coord pos; + char elt; +}; + +class GridIterator { + Grid const& grid_; + std::int64_t x_, y_; + + public: + GridIterator(Grid const& grid, std::int64_t x, std::int64_t y) + : grid_{grid}, x_{x}, y_{y} {} + + auto operator++() -> GridIterator&; + + auto operator*() -> GridElement; + + auto operator==(GridIterator const& rhs) const -> bool + { + return x_ == rhs.x_ && y_ == rhs.y_; + } +}; + struct Grid { std::vector rows; std::size_t columns; @@ -57,28 +81,16 @@ struct Grid { } result.rows.emplace_back(std::move(line)); } - } else { - result.columns = 0; } return result; } - /** - * @brief Apply the callback function across all elements of the grid. - * - * @tparam F Type of callback - * @param f Callback function - */ - template F> - auto each(F f = F{}) const -> void { - auto const h = rows.size(); - for (std::size_t y = 0; y < h; y++) { - auto const& row = rows[y]; - auto const w = row.size(); - for (std::size_t x = 0; x < w; x++) { - f(Coord{static_cast(x), static_cast(y)}, row[x]); - } - } + auto begin() const -> GridIterator { + return GridIterator{*this, 0, 0}; + } + + auto end() const -> GridIterator { + return GridIterator{*this, 0, static_cast(rows.size())}; } }; diff --git a/lib/src/Grid.cpp b/lib/src/Grid.cpp new file mode 100644 index 0000000..ad9416c --- /dev/null +++ b/lib/src/Grid.cpp @@ -0,0 +1,19 @@ +#include "aocpp/Grid.hpp" + +namespace aocpp { +auto GridIterator::operator*() -> GridElement +{ + return {{x_, y_}, grid_[Coord{x_, y_}]}; +} + +auto GridIterator::operator++() -> GridIterator & +{ + if (++x_ == grid_.columns) + { + x_ = 0; + y_++; + } + + return *this; +} +} // namespace