This commit is contained in:
Eric Mertens 2022-11-11 17:46:56 -08:00
parent ce8a6a1c79
commit 68cde80601
3 changed files with 63 additions and 84 deletions

View File

@ -1,19 +1,14 @@
#include <algorithm> #include <algorithm>
#include <concepts>
#include <cstdint> #include <cstdint>
#include <iostream> #include <iostream>
#include <iomanip>
#include <fstream>
#include <iterator> #include <iterator>
#include <stdexcept> #include <map>
#include <vector>
#include <set> #include <set>
#include <stdexcept>
#include <string> #include <string>
#include <tuple> #include <tuple>
#include <bitset> #include <vector>
#include <deque>
#include <cctype>
#include <queue>
#include <map>
#include <aocpp/Startup.hpp> #include <aocpp/Startup.hpp>
#include <aocpp/Coord.hpp> #include <aocpp/Coord.hpp>
@ -39,7 +34,7 @@ struct Map {
}; };
auto FindBugs(Map const& map) { auto FindBugs(Map const& map) {
std::set<Coord> result; std::vector<Coord> result;
std::int64_t w = map.rows[0].size(); std::int64_t w = map.rows[0].size();
std::int64_t h = map.rows.size(); std::int64_t h = map.rows.size();
@ -47,92 +42,72 @@ auto FindBugs(Map const& map) {
for (std::int64_t x = 0; x < w; x++) { for (std::int64_t x = 0; x < w; x++) {
for (std::int64_t y = 0; y < h; y++) { for (std::int64_t y = 0; y < h; y++) {
Coord const c = {x,y}; Coord const c = {x,y};
if (map[c] == '#') result.insert(c); if (map[c] == '#') result.push_back(c);
} }
} }
return result; return result;
} }
auto Neighbor1(Coord c) { struct Neighbor1 {
std::vector<Coord> result; auto operator()(Coord c, auto f) const -> void {
result.reserve(4); if (c.x > 0) f(Left(c));
if (c.x > 0) result.push_back(Left(c)); if (c.x < 4) f(Right(c));
if (c.x < 4) result.push_back(Right(c)); if (c.y > 0) f(Up(c));
if (c.y > 0) result.push_back(Up(c)); if (c.y < 4) f(Down(c));
if (c.y < 4) result.push_back(Down(c));
return result;
}
auto Neighbor2(std::pair<Coord, std::int64_t> cd) {
auto [c,d] = cd;
std::vector<std::pair<Coord, std::int64_t>> 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) { struct Neighbor2 {
for (std::int64_t yi = 0; yi < 5; yi++) { using C3 = std::pair<Coord, std::int64_t>;
result.push_back({{0,yi},d+1}); auto operator()(C3 cd, auto f) const -> void {
} auto const [c,d] = cd;
} else if (c.x < 4) {
result.push_back({Right(c),d}); auto left_neighbors = [&f](Coord c, std::int64_t d, auto k_, auto k) {
} else { c = k_(c);
result.push_back({{3,2},d-1}); if (c.x == 1 && c.y == 0) {
for (std::int64_t yi = -2; yi <= 2; yi++) {
f({k({2,yi}),d+1});
}
} else if (c.x > -2) {
f({k(Left(c)),d});
} else {
f({k({-1,0}),d-1});
}
};
auto id = [](Coord i) { return i; };
left_neighbors(c, d, id, id);
left_neighbors(c, d, Turn180, Turn180);
left_neighbors(c, d, CW, CCW);
left_neighbors(c, d, CCW, CW);
} }
};
if (c.x == 2 && c.y == 3) { template<typename F, typename C>
for (std::int64_t xi = 0; xi < 5; xi++) { auto Step(std::vector<C> const& bugs, F with_neighbors = F{})
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<class F, class C>
auto Step(std::set<C> const& bugs, F neighbors)
{ {
std::map<C, int> adjacent; std::map<C, int> adjacent;
for (auto const& x : bugs) { for (auto const& x : bugs) {
for (auto const& n : neighbors(x)) { with_neighbors(x, [&adjacent](C n) -> void { adjacent[n]++; });
adjacent[n]++;
}
} }
std::set<C> result; std::vector<C> result;
for (auto const& [k,v] : adjacent) { for (auto const& [k,v] : adjacent) {
switch (v) { switch (v) {
case 1: result.insert(k); break; case 1:
case 2: if (!bugs.contains(k)) result.insert(k); break; result.push_back(k);
break;
case 2:
if (!std::binary_search(bugs.begin(), bugs.end(), k)) {
result.push_back(k);
break;
}
} }
} }
return result; return result;
} }
auto Bio(std::set<Coord> const& bugs) -> std::uint32_t { auto Bio(std::vector<Coord> const& bugs) -> std::uint32_t {
std::uint32_t result = 0; std::uint32_t result = 0;
for (auto const& c : bugs) { for (auto const& c : bugs) {
result |= 1U << (5 * c.y + c.x); result |= 1U << (5 * c.y + c.x);
@ -140,23 +115,23 @@ auto Bio(std::set<Coord> const& bugs) -> std::uint32_t {
return result; return result;
} }
auto Part1(std::set<Coord> const& bugs) -> std::uint32_t { auto Part1(std::vector<Coord> const& bugs) -> std::uint32_t {
auto cursor = bugs; auto cursor = bugs;
std::set<std::uint32_t> seen; std::set<std::uint32_t> seen;
std::uint32_t bio; std::uint32_t bio;
while (seen.insert(bio = Bio(cursor)).second) { while (seen.insert(bio = Bio(cursor)).second) {
cursor = Step(cursor, Neighbor1); cursor = Step<Neighbor1>(cursor);
} }
return bio; return bio;
} }
auto Part2(std::set<Coord> const& bugs) { auto Part2(std::vector<Coord> const& bugs) {
std::set<std::pair<Coord,std::int64_t>> bugs2; std::vector<std::pair<Coord,std::int64_t>> bugs2;
for (auto const& x : bugs) { for (auto const& [x,y] : bugs) {
bugs2.insert({x,0}); bugs2.push_back({{x-2,y-2},0});
} }
for (int i = 0; i < 200; i++) { for (int i = 0; i < 200; i++) {
bugs2 = Step(bugs2, Neighbor2); bugs2 = Step<Neighbor2>(bugs2);
} }
return bugs2.size(); return bugs2.size();
} }

View File

@ -40,6 +40,8 @@ auto CW(Coord) -> Coord;
/// Rotate counter-clockwise /// Rotate counter-clockwise
auto CCW(Coord) -> Coord; auto CCW(Coord) -> Coord;
auto Turn180(Coord) -> Coord;
auto Norm1(Coord) -> std::int64_t; auto Norm1(Coord) -> std::int64_t;
/// Add two coordinates pairwise /// Add two coordinates pairwise

View File

@ -62,9 +62,11 @@ auto CW(Coord c) -> Coord {
} }
auto CCW(Coord c) -> Coord { auto CCW(Coord c) -> Coord {
c = Invert(c); return CW(CW(CW(c)));
c.y = -c.y; }
return c;
auto Turn180(Coord c) -> Coord {
return CW(CW(c));
} }
auto Norm1(Coord c) -> std::int64_t { auto Norm1(Coord c) -> std::int64_t {