aocpp/2019/24.cpp

143 lines
3.3 KiB
C++
Raw Normal View History

2022-11-10 22:59:40 -08:00
#include <algorithm>
2022-11-11 17:46:56 -08:00
#include <concepts>
2022-11-10 22:59:40 -08:00
#include <cstdint>
#include <iostream>
#include <iterator>
2022-11-11 17:46:56 -08:00
#include <map>
2022-11-10 22:59:40 -08:00
#include <set>
2022-11-13 11:48:12 -08:00
#include <sstream>
2022-11-11 17:46:56 -08:00
#include <stdexcept>
2022-11-10 22:59:40 -08:00
#include <string>
#include <tuple>
2022-11-11 17:46:56 -08:00
#include <vector>
2022-11-10 22:59:40 -08:00
2022-11-13 11:48:12 -08:00
#include <doctest.h>
2022-11-10 22:59:40 -08:00
#include <aocpp/Startup.hpp>
#include <aocpp/Coord.hpp>
2022-11-11 21:39:36 -08:00
#include <aocpp/Grid.hpp>
2022-11-10 22:59:40 -08:00
using namespace aocpp;
namespace {
2022-11-11 21:39:36 -08:00
auto FindBugs(Grid const& grid) -> std::vector<Coord> {
2022-11-11 17:46:56 -08:00
std::vector<Coord> result;
2022-11-10 22:59:40 -08:00
2022-11-11 21:39:36 -08:00
std::int64_t w = grid.rows[0].size();
std::int64_t h = grid.rows.size();
2022-11-10 22:59:40 -08:00
2022-11-11 21:39:36 -08:00
grid.each([&](Coord c, char v) {
if (v == '#') result.push_back(c);
});
2022-11-10 22:59:40 -08:00
return result;
}
2022-11-11 17:46:56 -08:00
struct Neighbor1 {
auto operator()(Coord c, auto f) const -> void {
if (c.x > 0) f(Left(c));
if (c.x < 4) f(Right(c));
if (c.y > 0) f(Up(c));
if (c.y < 4) f(Down(c));
2022-11-10 22:59:40 -08:00
}
2022-11-11 17:46:56 -08:00
};
2022-11-10 22:59:40 -08:00
2022-11-11 17:46:56 -08:00
struct Neighbor2 {
using C3 = std::pair<Coord, std::int64_t>;
auto operator()(C3 cd, auto f) const -> void {
2022-11-11 21:39:36 -08:00
auto left_neighbors = [cd,f](auto k_, auto k) {
auto const [c,d] = cd;
2022-11-11 19:51:14 -08:00
auto c_ = k_(c);
if (c_.x == 1 && c_.y == 0) {
2022-11-11 17:46:56 -08:00
for (std::int64_t yi = -2; yi <= 2; yi++) {
f({k({2,yi}),d+1});
}
2022-11-11 19:51:14 -08:00
} else if (c_.x > -2) {
f({k(Left(c_)),d});
2022-11-11 17:46:56 -08:00
} else {
f({k({-1,0}),d-1});
}
};
auto id = [](Coord i) { return i; };
2022-11-11 19:51:14 -08:00
left_neighbors(id, id);
left_neighbors(Turn180, Turn180);
left_neighbors(CW, CCW);
left_neighbors(CCW, CW);
2022-11-10 22:59:40 -08:00
}
2022-11-11 17:46:56 -08:00
};
2022-11-10 22:59:40 -08:00
2022-11-11 20:00:43 -08:00
template<std::totally_ordered C, std::invocable<C, void(C const&)> F>
2022-11-11 17:46:56 -08:00
auto Step(std::vector<C> const& bugs, F with_neighbors = F{})
2022-11-10 22:59:40 -08:00
{
std::map<C, int> adjacent;
for (auto const& x : bugs) {
2022-11-11 20:00:43 -08:00
with_neighbors(x, [&adjacent](C const& n) -> void { adjacent[n]++; });
2022-11-10 22:59:40 -08:00
}
2022-11-11 17:46:56 -08:00
std::vector<C> result;
2022-11-10 22:59:40 -08:00
for (auto const& [k,v] : adjacent) {
switch (v) {
2022-11-11 17:46:56 -08:00
case 1:
result.push_back(k);
break;
case 2:
if (!std::binary_search(bugs.begin(), bugs.end(), k)) {
result.push_back(k);
}
break;
2022-11-10 22:59:40 -08:00
}
}
return result;
}
2022-11-11 17:46:56 -08:00
auto Bio(std::vector<Coord> const& bugs) -> std::uint32_t {
2022-11-10 22:59:40 -08:00
std::uint32_t result = 0;
for (auto const& c : bugs) {
result |= 1U << (5 * c.y + c.x);
}
return result;
}
2022-11-11 17:46:56 -08:00
auto Part1(std::vector<Coord> const& bugs) -> std::uint32_t {
2022-11-10 22:59:40 -08:00
auto cursor = bugs;
std::set<std::uint32_t> seen;
2022-11-11 15:10:56 -08:00
std::uint32_t bio;
while (seen.insert(bio = Bio(cursor)).second) {
2022-11-11 20:00:43 -08:00
cursor = Step<Coord, Neighbor1>(cursor);
2022-11-10 22:59:40 -08:00
}
2022-11-11 15:10:56 -08:00
return bio;
2022-11-10 22:59:40 -08:00
}
2022-11-13 11:48:12 -08:00
auto Part2(std::vector<Coord> const& bugs, int minutes) {
2022-11-11 20:00:43 -08:00
std::vector<Neighbor2::C3> bugs2;
2022-11-11 17:46:56 -08:00
for (auto const& [x,y] : bugs) {
bugs2.push_back({{x-2,y-2},0});
2022-11-10 22:59:40 -08:00
}
2022-11-13 11:48:12 -08:00
for (int i = 0; i < minutes; i++) {
2022-11-11 20:00:43 -08:00
bugs2 = Step<Neighbor2::C3, Neighbor2>(bugs2);
2022-11-10 22:59:40 -08:00
}
return bugs2.size();
}
} // namespace
2022-11-13 11:48:12 -08:00
TEST_SUITE("documented examples") {
TEST_CASE("part 1") {
std::istringstream in {"....#\n#..#.\n#..##\n..#..\n#....\n"};
REQUIRE(Part1(FindBugs(Grid::Parse(in))) == 2129920);
}
TEST_CASE("part 2") {
std::istringstream in {"....#\n#..#.\n#.?##\n..#..\n#....\n"};
REQUIRE(Part2(FindBugs(Grid::Parse(in)), 10) == 99);
}
}
2022-11-10 22:59:40 -08:00
auto main(int argc, char** argv) -> int {
auto const bugs = FindBugs(Grid::Parse(*Startup(argc, argv)));
2022-11-10 22:59:40 -08:00
std::cout << "Part 1: " << Part1(bugs) << std::endl;
2022-11-13 11:48:12 -08:00
std::cout << "Part 2: " << Part2(std::move(bugs), 200) << std::endl;
2022-11-10 22:59:40 -08:00
}