#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace aocpp; namespace { struct Map { std::vector rows; auto operator[](Coord c) -> char& { return rows[c.y][c.x]; } auto operator[](Coord c) const -> char { return rows[c.y][c.x]; } static auto Parse(std::istream & in) -> Map { Map result; std::string line; while (std::getline(in, line)) { result.rows.emplace_back(std::move(line)); } return {result}; } }; auto FindBugs(Map const& map) { std::set result; std::int64_t w = map.rows[0].size(); std::int64_t h = map.rows.size(); for (std::int64_t x = 0; x < w; x++) { for (std::int64_t y = 0; y < h; y++) { Coord const c = {x,y}; if (map[c] == '#') result.insert(c); } } return result; } auto Neighbor1(Coord c) { std::vector result; result.reserve(4); if (c.x > 0) result.push_back(Left(c)); if (c.x < 4) result.push_back(Right(c)); if (c.y > 0) result.push_back(Up(c)); if (c.y < 4) result.push_back(Down(c)); return result; } auto Neighbor2(std::pair cd) { auto [c,d] = cd; std::vector> result; result.reserve(8); if (c.x == 3 && c.y == 2) { for (std::int64_t yi = 0; yi < 5; yi++) { result.push_back({{4,yi},d+1}); } } else if (c.x > 0) { result.push_back({Left(c),d}); } else { result.push_back({{1,2},d-1}); } if (c.x == 1 && c.y == 2) { for (std::int64_t yi = 0; yi < 5; yi++) { result.push_back({{0,yi},d+1}); } } else if (c.x < 4) { result.push_back({Right(c),d}); } else { result.push_back({{3,2},d-1}); } if (c.x == 2 && c.y == 3) { for (std::int64_t xi = 0; xi < 5; xi++) { result.push_back({{xi,4},d+1}); } } else if (c.y > 0) { result.push_back({Up(c),d}); } else { result.push_back({{2,1},d-1}); } if (c.x == 2 && c.y == 1) { for (std::int64_t xi = 0; xi < 5; xi++) { result.push_back({{xi,0},d+1}); } } else if (c.y < 4) { result.push_back({Down(c),d}); } else { result.push_back({{2,3},d-1}); } return result; } template auto Step(std::set const& bugs, F neighbors) { std::map adjacent; for (auto const& x : bugs) { for (auto const& n : neighbors(x)) { adjacent[n]++; } } std::set result; for (auto const& [k,v] : adjacent) { switch (v) { case 1: result.insert(k); break; case 2: if (!bugs.contains(k)) result.insert(k); break; } } return result; } auto Bio(std::set const& bugs) -> std::uint32_t { std::uint32_t result = 0; for (auto const& c : bugs) { result |= 1U << (5 * c.y + c.x); } return result; } auto Part1(std::set const& bugs) -> std::uint32_t { auto cursor = bugs; std::set seen; std::uint32_t bio; while (seen.insert(bio = Bio(cursor)).second) { cursor = Step(cursor, Neighbor1); } return bio; } auto Part2(std::set const& bugs) { std::set> bugs2; for (auto const& x : bugs) { bugs2.insert({x,0}); } for (int i = 0; i < 200; i++) { bugs2 = Step(bugs2, Neighbor2); } return bugs2.size(); } } // namespace auto main(int argc, char** argv) -> int { auto const bugs = FindBugs(Map::Parse(Startup(argc, argv))); std::cout << "Part 1: " << Part1(bugs) << std::endl; std::cout << "Part 2: " << Part2(std::move(bugs)) << std::endl; }