AoC code coverage
Current view: top level - puzzles/2024 - Day16.cpp (source / functions) Coverage Total Hit
Test: master Lines: 100.0 % 115 115
Test Date: 2025-07-28 10:53:57 Functions: 100.0 % 10 10

            Line data    Source code
       1              : #include "PuzzleImpl.h"
       2              : 
       3              : #include "Grid2d.h"
       4              : #include "LinewiseInput.h"
       5              : 
       6              : #include <experimental/mdspan>
       7              : 
       8              : #include <algorithm>
       9              : #include <cstddef>
      10              : #include <queue>
      11              : #include <ranges>
      12              : #include <set>
      13              : #include <string_view>
      14              : 
      15              : using namespace std::literals;
      16              : 
      17              : namespace {
      18              : 
      19              : using VertexId = std::array<int, 3u>;
      20              : 
      21              : int constexpr numDirections = 4;
      22              : std::array<Vec2<int>, numDirections> constexpr dirs{{{0, 1}, {1, 0}, {0, -1}, {-1, 0}}};
      23              : 
      24        80896 : constexpr VertexId turnRight(VertexId const vid) {
      25        80896 :   auto [x, y, d] = vid;
      26        80896 :   return {x, y, d == 3 ? 0 : d + 1};
      27        80896 : }
      28              : 
      29        80896 : constexpr VertexId turnLeft(VertexId const vid) {
      30        80896 :   auto [x, y, d] = vid;
      31        80896 :   return {x, y, d == 0 ? 3 : d - 1};
      32        80896 : }
      33              : 
      34        80896 : constexpr VertexId moveForward(VertexId const vid) {
      35        80896 :   auto [x, y, d] = vid;
      36        80896 :   return {x + dirs[d].x(), y + dirs[d].y(), d};
      37        80896 : }
      38              : 
      39              : struct VertexScore {
      40       831216 :   constexpr bool operator<(VertexScore const &other) const { return score > other.score; }
      41              : 
      42              :   VertexId id;
      43              :   int score;
      44              : };
      45              : 
      46            2 : VertexId startVertex(Grid2d<char> const &map) {
      47            2 :   auto [sourceX, sourceY] = map.find('S');
      48            2 :   return {sourceX, sourceY, 1};
      49            2 : }
      50              : 
      51            2 : std::array<VertexId, 4u> endVertices(Grid2d<char> const &map) {
      52            2 :   auto [endX, endY] = map.find('E');
      53            2 :   return {{{endX, endY, 0}, {endX, endY, 1}, {endX, endY, 2}, {endX, endY, 3}}};
      54            2 : }
      55              : 
      56              : } // namespace
      57              : 
      58            1 : template <> size_t part1<2024, 16>(std::string_view const input) {
      59            1 :   Grid2d<char> const map = LinewiseInput(input).makeCharGrid2d();
      60            1 :   std::vector<int> distData(static_cast<size_t>(map.xSize() * map.ySize() * numDirections),
      61            1 :                             std::numeric_limits<int>::max());
      62            1 :   std::experimental::mdspan const dist(distData.data(), map.xSize(), map.ySize(), numDirections);
      63              : 
      64            1 :   VertexId const source = startVertex(map);
      65              : 
      66            1 :   std::priority_queue<VertexScore> queue;
      67              : 
      68            1 :   dist[source] = 0;
      69            1 :   queue.emplace(source, 0);
      70              : 
      71        40699 :   while (!queue.empty()) {
      72        40698 :     auto [u, p] = queue.top();
      73        40698 :     queue.pop();
      74        40698 :     if (p != dist[u])
      75          250 :       continue;
      76        40448 :     {
      77        40448 :       auto v = moveForward(u);
      78        40448 :       if (map[v[0], v[1]] != '#') {
      79        20848 :         int alt = dist[u] + 1;
      80        20848 :         if (alt < dist[v]) {
      81        10934 :           dist[v] = alt;
      82        10934 :           queue.emplace(v, alt);
      83        10934 :         }
      84        20848 :       }
      85        40448 :     }
      86        80896 :     for (auto v : {turnLeft(u), turnRight(u)}) {
      87        80896 :       int alt = dist[u] + 1000;
      88        80896 :       if (alt < dist[v]) {
      89        29763 :         dist[v] = alt;
      90        29763 :         queue.emplace(v, alt);
      91        29763 :       }
      92        80896 :     }
      93        40448 :   }
      94              : 
      95            1 :   return std::ranges::min(endVertices(map) |
      96            4 :                           std::views::transform([&](auto const &v) { return dist[v]; }));
      97            1 : }
      98              : 
      99            1 : template <> size_t part2<2024, 16>(std::string_view const input) {
     100            1 :   Grid2d<char> const map = LinewiseInput(input).makeCharGrid2d();
     101            1 :   std::vector<int> distData(static_cast<size_t>(map.xSize() * map.ySize() * numDirections),
     102            1 :                             std::numeric_limits<int>::max());
     103            1 :   std::vector<std::vector<VertexId>> predData(
     104            1 :       static_cast<size_t>(map.xSize() * map.ySize() * numDirections));
     105            1 :   std::experimental::mdspan const dist(distData.data(), map.xSize(), map.ySize(), numDirections);
     106            1 :   std::experimental::mdspan const pred(predData.data(), map.xSize(), map.ySize(), numDirections);
     107              : 
     108            1 :   VertexId const source = startVertex(map);
     109              : 
     110            1 :   std::priority_queue<VertexScore> queue;
     111              : 
     112            1 :   dist[source] = 0;
     113            1 :   queue.emplace(source, 0);
     114              : 
     115        40699 :   while (!queue.empty()) {
     116        40698 :     auto [u, p] = queue.top();
     117        40698 :     queue.pop();
     118        40698 :     if (p != dist[u])
     119          250 :       continue;
     120        40448 :     {
     121        40448 :       auto v = moveForward(u);
     122        40448 :       if (map[v[0], v[1]] != '#') {
     123        20848 :         int alt = dist[u] + 1;
     124        20848 :         if (alt < dist[v]) {
     125        10934 :           pred[v].assign(1u, u);
     126        10934 :           dist[v] = alt;
     127        10934 :           queue.emplace(v, alt);
     128        10934 :         } else if (alt == dist[v]) {
     129          223 :           pred[v].push_back(u);
     130          223 :         }
     131        20848 :       }
     132        40448 :     }
     133        80896 :     for (auto v : {turnLeft(u), turnRight(u)}) {
     134        80896 :       int alt = dist[u] + 1000;
     135        80896 :       if (alt < dist[v]) {
     136        29763 :         pred[v].assign(1u, u);
     137        29763 :         dist[v] = alt;
     138        29763 :         queue.emplace(v, alt);
     139        51133 :       } else if (alt == dist[v]) {
     140         9505 :         pred[v].push_back(u);
     141         9505 :       }
     142        80896 :     }
     143        40448 :   }
     144              : 
     145            1 :   auto ev = endVertices(map);
     146            1 :   int const minScore =
     147            4 :       std::ranges::min(ev | std::views::transform([&](auto const &v) { return dist[v]; }));
     148              : 
     149            1 :   std::set<Vec2<int>> goodSeats;
     150            1 :   std::queue<VertexId> q;
     151              : 
     152            4 :   for (auto const &e : ev) {
     153            4 :     if (dist[e] == minScore)
     154            1 :       q.push(e);
     155            4 :   }
     156              : 
     157         5836 :   while (!q.empty()) {
     158         5835 :     VertexId cur = q.front();
     159         5835 :     q.pop();
     160         5835 :     goodSeats.emplace(cur[0], cur[1]);
     161              : 
     162         5835 :     for (VertexId p : pred[cur])
     163         5834 :       q.push(p);
     164         5835 :   }
     165              : 
     166            1 :   return goodSeats.size();
     167            1 : }
        

Generated by: LCOV version 2.0-1