Advertisement
Guest User

aoc2023-day21-cpp

a guest
Dec 21st, 2023
63
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 2.97 KB | None | 0 0
  1. #include <algorithm>
  2. #include <deque>
  3. #include <fstream>
  4. #include <vector>
  5. #include <map>
  6. #include <chrono>
  7.  
  8. #include <range/v3/all.hpp>
  9. #include <fmt/format.h>
  10. #include <fmt/chrono.h>
  11. #include <flux.hpp>
  12.  
  13. struct P {
  14.     int x{}, y{};
  15.     int parity() const { return (x + y) & 1; }
  16.     auto operator<=>(P const&) const = default;
  17. };
  18.  
  19. using Grid = std::vector<std::vector<char>>;
  20.  
  21. std::vector<P> reachableIn(Grid const& g, int steps, P start) {
  22.     std::deque<std::pair<P, int>> q{{start, 0}};
  23.     std::map<P, int> seen{{start, 0}};
  24.  
  25.     while(!q.empty()) {
  26.         auto [n, d] = q.front();
  27.         q.pop_front();
  28.  
  29.         for(P const& p : {P{n.x-1, n.y}, P{n.x+1, n.y}, P{n.x, n.y-1}, P{n.x, n.y+1}}) {
  30.             if(p.y < 0 || p.x < 0 || p.y >= g.size() || p.x >= g.at(p.y).size() || g.at(p.y).at(p.x) == '#')
  31.                 continue;
  32.             if(!seen.contains(p)) {
  33.                 seen[p] = d + 1;
  34.                 q.push_back({p, d+1});
  35.             }
  36.         }
  37.     }
  38.  
  39.     return seen | std::views::filter([&](auto x) { return x.second <= steps; }) | std::views::transform([](auto x) { return x.first; }) | ranges::to_vector;
  40.  
  41. }
  42.  
  43. long solve1(Grid const& g, P start) {
  44.     return std::ranges::ssize(reachableIn(g, 64, start) | std::views::filter([=](P p) { return p.parity() == start.parity(); }) | ranges::to_vector);
  45. }
  46.  
  47. long solve2(Grid const& g, P start) {
  48.  
  49.     long steps = 26501365;
  50.     long size = g.size();
  51.     assert(size == 131);
  52.     assert((steps - size/2) % size == 0);
  53.     assert(steps % 2 == 1 && size % 2 == 1);
  54.  
  55.     long d = steps/size;
  56.     long k = (2 * d + 1);
  57.     long k1 = k*k/2;
  58.  
  59.     auto sq = [](long x) { return x * x; };
  60.     auto center = reachableIn(g, size/2, start);
  61.     auto full = reachableIn(g, 2*size, start);
  62.  
  63.     long d0 = std::ranges::count_if(center, [=](P p) { return p.parity() != start.parity(); });
  64.     long dr = std::ranges::count_if(full, [=](P p) { return p.parity() != start.parity(); }) - d0;
  65.     long dn0 = center.size() - d0;
  66.     long dnr = dr + d0 - dn0;
  67.  
  68.     long r = sq(2 * d + 1) / 2;
  69.     auto [rplus, rminus] = std::make_pair(r/2, r/2);
  70.     long z = sq(2 * d + 1) / 2 + 1;
  71.     long zplus = sq(1 + 2*(d/2));
  72.     long zminus = z - zplus;
  73.  
  74.     return zplus * d0 + zminus * dn0 + rplus * dr + rminus * dnr;
  75. }
  76.  
  77. Grid parse(std::string filename) {
  78.     std::ifstream in(std::move(filename));
  79.     return flux::getlines(in).map([](std::string s) { return flux::from(std::move(s)).to<std::vector<char>>(); }).to<Grid>();
  80. }
  81.  
  82. int main(int argc, char* argv[]) {
  83.     auto time = std::chrono::steady_clock::now();
  84.     auto g = parse(argc > 1 ? argv[1] : "../task1.txt");
  85.  
  86.     P start;
  87.     for(int y = 0; y < g.size(); ++y)
  88.         for(int x = 0; x < g.at(y).size(); ++x)
  89.             if(g.at(y).at(x) == 'S')
  90.                 start = P{.x = x, .y = y};
  91.  
  92.     fmt::println("task1={}\ntask2={}", solve1(g, start), solve2(g, start));
  93.     fmt::println("took {}", std::chrono::steady_clock::now() - time);
  94. }
  95.  
  96.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement