diff --git a/2019/17.cpp b/2019/17.cpp index d29e0e9..5a45333 100644 --- a/2019/17.cpp +++ b/2019/17.cpp @@ -17,7 +17,7 @@ namespace { auto GatherOutput(Machine m) -> Grid { - Grid grid; + std::vector rows; bool eol = true; // next output starts a new line Run(m, []() -> ValueType { @@ -25,16 +25,16 @@ auto GatherOutput(Machine m) -> Grid }, [&](ValueType c) -> void { if (eol) { - grid.rows.emplace_back(); + rows.emplace_back(); eol = false; } if ('\n' == c) { eol = true; } else { - grid.rows.back().push_back(static_cast(c));} + rows.back().push_back(static_cast(c));} } ); - return grid; + return Grid{std::move(rows)}; } /// Find all the 4-way intersections. diff --git a/2019/20.cpp b/2019/20.cpp index fa7f882..a1d33d3 100644 --- a/2019/20.cpp +++ b/2019/20.cpp @@ -35,8 +35,8 @@ using Distances = std::map>>; auto FindPortals(Grid const& grid) -> Portals { Portals portals; - std::int64_t w = grid.rows[0].size(); - std::int64_t h = grid.rows.size(); + std::int64_t w = grid.Cols(); + std::int64_t h = grid.Rows(); for (std::int64_t x = 1; x < w-1; x++) { for (std::int64_t y = 1; y < h-1; y++) { diff --git a/2019/24.cpp b/2019/24.cpp index 72e6620..70156cb 100644 --- a/2019/24.cpp +++ b/2019/24.cpp @@ -24,8 +24,8 @@ namespace { auto FindBugs(Grid const& grid) -> std::vector { std::vector result; - std::int64_t w = grid.rows[0].size(); - std::int64_t h = grid.rows.size(); + std::int64_t w = grid.Cols(); + std::int64_t h = grid.Rows(); grid.each([&](Coord c, char v) { if (v == '#') result.push_back(c); diff --git a/2020/03.cpp b/2020/03.cpp index a06e007..fd4e005 100644 --- a/2020/03.cpp +++ b/2020/03.cpp @@ -22,11 +22,12 @@ namespace { auto Ski(Grid const& grid, Coord step) -> std::size_t { - std::size_t const w = grid.rows[0].size(); + std::size_t const w = grid.Cols(); + std::size_t const h = grid.Rows(); std::size_t trees {0}; Coord here {0,0}; - while(here.y < grid.rows.size()) { + while(here.y < h) { if (grid[here] == '#') trees++; here += step; while (here.x >= w) { here.x -= w; } diff --git a/lib/include/aocpp/Grid.hpp b/lib/include/aocpp/Grid.hpp index 990ad77..5f17b77 100644 --- a/lib/include/aocpp/Grid.hpp +++ b/lib/include/aocpp/Grid.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include @@ -12,6 +13,21 @@ namespace aocpp { struct Grid { std::vector rows; + std::size_t columns; + + Grid() : rows{}, columns{} {} + explicit Grid(std::vector rows) : rows(std::move(rows)) + { + columns = rows.empty() ? 0 : rows[0].size(); + for (std::size_t i = 1; i < rows.size(); i++) { + if (rows[i].size() != columns) { + throw std::runtime_error{"grid not rectangular"}; + } + } + } + + auto Rows() const -> std::size_t { return rows.size(); } + auto Cols() const -> std::size_t { return columns; } auto contains(Coord c) const -> bool { return @@ -24,13 +40,26 @@ struct Grid { auto operator[](Coord c) -> char& { return rows[c.y][c.x]; } auto operator[](Coord c) const -> char { return rows[c.y][c.x]; } + /// @brief Parse a rectangular grid from a stream + /// @param in input stream read until eof + /// @return parsed grid + /// @throw std::runtime\_error when grid is not rectangular static auto Parse(std::istream & in) -> Grid { Grid result; std::string line; - while (std::getline(in, line)) { + if (std::getline(in, line)) { + result.columns = line.size(); result.rows.emplace_back(std::move(line)); + while (std::getline(in, line)) { + if (line.size() != result.columns) { + throw std::runtime_error{"bad grid"}; + } + result.rows.emplace_back(std::move(line)); + } + } else { + result.columns = 0; } - return {result}; + return result; } template