Make Grid iterable

This commit is contained in:
Eric Mertens 2024-09-05 20:10:34 -07:00
parent 9e6223f886
commit d6fc0396cb
11 changed files with 77 additions and 46 deletions

View File

@ -17,13 +17,13 @@ auto Part1(aocpp::Grid const &input, std::int64_t reps = 10'000) -> std::int64_t
std::unordered_set<aocpp::Coord> infected; std::unordered_set<aocpp::Coord> infected;
// Initialize set of infected locations // Initialize set of infected locations
input.each([&infected](auto const pos, auto const cell) for (auto [pos, cell] : input)
{ {
if (cell == '#') if (cell == '#')
{ {
infected.insert(pos); infected.insert(pos);
} }
}); }
// Start in the middle // Start in the middle
aocpp::Coord pos; 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<aocpp::Coord, char> cells; std::unordered_map<aocpp::Coord, char> cells;
// Initialize set of infected locations // Initialize set of infected locations
input.each([&cells](auto const pos, auto const cell) for (auto [pos, cell] : input)
{ {
if (cell == '#') if (cell == '#')
{ {
cells.try_emplace(pos, '#'); cells.try_emplace(pos, '#');
} }
}); }
// Start in the middle // Start in the middle
aocpp::Coord pos; aocpp::Coord pos;

View File

@ -60,11 +60,11 @@ Game::Game(Grid grid)
, debug_out_{} , debug_out_{}
{ {
// set each unit to its initial hit points // set each unit to its initial hit points
grid_.each([&](auto k, auto v) { for (auto [k, v] : grid_) {
if (IsUnit(v)) { if (IsUnit(v)) {
units_[k] = initial_hp; units_[k] = initial_hp;
} }
}); }
} }
// Render the game as seen in the examples // Render the game as seen in the examples
@ -166,9 +166,9 @@ auto Game::Simulate() -> std::optional<int> {
// Detect when no targets remain for this unit and end the game // Detect when no targets remain for this unit and end the game
auto game_over = true; auto game_over = true;
grid_.each([&](auto k, auto v) { for (auto [k, v] : grid_) {
if (IsOpposed(active_team, v)) game_over = false; if (IsOpposed(active_team, v)) game_over = false;
}); }
if (game_over) { if (game_over) {
int total_hp = 0; int total_hp = 0;
for (auto const& [_,v] : units_) { total_hp += v; } for (auto const& [_,v] : units_) { total_hp += v; }

View File

@ -70,23 +70,23 @@ auto ClearView(Grid const& grid, Coord src, Coord dst) -> bool {
auto Part1(Grid const& grid) { auto Part1(Grid const& grid) {
std::size_t best = 0; std::size_t best = 0;
Coord base {}; Coord base {};
grid.each([&](Coord src, char s) { for (auto [src, s] : grid) {
if ('#' == s) { if ('#' == s) {
std::size_t visible = 0; std::size_t visible = 0;
grid.each([&](Coord dst, char d){ for (auto [dst, d] : grid) {
if ('#' == d && src != dst) { if ('#' == d && src != dst) {
if (ClearView(grid, src, dst)) { if (ClearView(grid, src, dst)) {
visible++; visible++;
} }
} }
}); }
if (visible > best) { if (visible > best) {
best = visible; best = visible;
base = src; base = src;
} }
} }
}); }
return std::make_pair(best, base); return std::make_pair(best, base);
} }
@ -94,11 +94,11 @@ auto Part2(Grid const& grid, Coord base, std::size_t n) {
std::map<Rational<std::int64_t>, std::vector<Coord>> targets; std::map<Rational<std::int64_t>, std::vector<Coord>> targets;
// arrange all the other asteroids by their angle relative to the base // 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 == '#') { if (c != base && v == '#') {
targets[angle(c-base)].push_back(c); targets[angle(c-base)].push_back(c);
} }
}); }
// Sort to vectors per angle such that the nearest asteroids are at // Sort to vectors per angle such that the nearest asteroids are at
// the end of the list // the end of the list

View File

@ -66,14 +66,14 @@ auto ComputePath(Grid const& grid)
{ {
// Determine starting location and direction // Determine starting location and direction
Coord start{}, step{}; Coord start{}, step{};
grid.each([&](Coord c, char v) { for (auto [c, v] : grid) {
switch (v) { switch (v) {
case '^': start = c; step = { 0, -1}; break; case '^': start = c; step = { 0, -1}; break;
case '>': start = c; step = { 0, 1}; break; case '>': start = c; step = { 0, 1}; break;
case '<': start = c; step = {-1, 0}; break; case '<': start = c; step = {-1, 0}; break;
case 'v': start = c; step = { 0, 1}; break; case 'v': start = c; step = { 0, 1}; break;
} }
}); }
auto is_path = [&](Coord c) { auto is_path = [&](Coord c) {
return grid.contains(c) && grid[c] == '#'; return grid.contains(c) && grid[c] == '#';

View File

@ -41,11 +41,11 @@ auto SetKey(Doors& doors, char key) {
auto FindFeatures(Grid const& grid) -> Features { auto FindFeatures(Grid const& grid) -> Features {
Features features; Features features;
grid.each([&](Coord c, char v) { for (auto [c, v] : grid) {
if ('#' != v && '.' != v) { if ('#' != v && '.' != v) {
features[v] = c; features[v] = c;
} }
}); }
return features; return features;
} }

View File

@ -27,9 +27,9 @@ auto FindBugs(Grid const& grid) -> std::vector<Coord> {
std::int64_t w = grid.Cols(); std::int64_t w = grid.Cols();
std::int64_t h = grid.Rows(); std::int64_t h = grid.Rows();
grid.each([&](Coord c, char v) { for (auto [c, v] : grid) {
if (v == '#') result.push_back(c); if (v == '#') result.push_back(c);
}); }
return result; return result;
} }

View File

@ -22,7 +22,7 @@ Dir directions[4] {Up, Down, Left, Right};
auto Part1(Grid const& grid) -> std::int64_t auto Part1(Grid const& grid) -> std::int64_t
{ {
std::int64_t result {0}; std::int64_t result {0};
grid.each([&](Coord const c, char const v) { for (auto [c, v] : grid) {
result += std::any_of( result += std::any_of(
std::begin(directions), std::end(directions), std::begin(directions), std::end(directions),
[&](Dir const dir) { [&](Dir const dir) {
@ -31,14 +31,14 @@ auto Part1(Grid const& grid) -> std::int64_t
} }
return true; return true;
}); });
}); }
return result; return result;
} }
auto Part2(Grid const& grid) -> std::int64_t auto Part2(Grid const& grid) -> std::int64_t
{ {
std::int64_t result {0}; std::int64_t result {0};
grid.each([&](Coord const c, char const v) { for (auto [c, v] : grid) {
auto score = std::transform_reduce( auto score = std::transform_reduce(
std::begin(directions), std::end(directions), std::begin(directions), std::end(directions),
std::int64_t{1}, std::multiplies(), // product std::int64_t{1}, std::multiplies(), // product
@ -51,7 +51,7 @@ auto Part2(Grid const& grid) -> std::int64_t
return count; return count;
}); });
if (result < score) result = score; if (result < score) result = score;
}); }
return result; return result;
} }

View File

@ -27,13 +27,13 @@ auto Parse(std::istream & in) -> std::tuple<Coord, std::vector<Coord>, Coord, Gr
auto& end = std::get<2>(result); auto& end = std::get<2>(result);
auto& grid = std::get<3>(result); auto& grid = std::get<3>(result);
grid.each([&](Coord c, char v) { for (auto [c, v] : grid) {
switch (v) { switch (v) {
case 'S': grid[c] = 'a'; start1 = c; break; case 'S': grid[c] = 'a'; start1 = c; break;
case 'E': grid[c] = 'z'; end = c; break; case 'E': grid[c] = 'z'; end = c; break;
case 'a': starts2.push_back(c); break; case 'a': starts2.push_back(c); break;
} }
}); }
return result; return result;
} }

View File

@ -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_include_directories(aocpp PUBLIC include)
target_link_libraries(aocpp Boost::headers) target_link_libraries(aocpp Boost::headers)

View File

@ -1,7 +1,6 @@
#ifndef AOCPP_GRID_HPP_ #ifndef AOCPP_GRID_HPP_
#define AOCPP_GRID_HPP_ #define AOCPP_GRID_HPP_
#include <concepts>
#include <iostream> #include <iostream>
#include <stdexcept> #include <stdexcept>
#include <type_traits> #include <type_traits>
@ -12,6 +11,31 @@
namespace aocpp { 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 { struct Grid {
std::vector<std::string> rows; std::vector<std::string> rows;
std::size_t columns; std::size_t columns;
@ -57,28 +81,16 @@ struct Grid {
} }
result.rows.emplace_back(std::move(line)); result.rows.emplace_back(std::move(line));
} }
} else {
result.columns = 0;
} }
return result; return result;
} }
/** auto begin() const -> GridIterator {
* @brief Apply the callback function across all elements of the grid. return GridIterator{*this, 0, 0};
*
* @tparam F Type of callback
* @param f Callback function
*/
template <std::invocable<Coord, char> 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<std::int64_t>(x), static_cast<std::int64_t>(y)}, row[x]);
}
} }
auto end() const -> GridIterator {
return GridIterator{*this, 0, static_cast<std::int64_t>(rows.size())};
} }
}; };

19
lib/src/Grid.cpp Normal file
View File

@ -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