AoC code coverage
Current view: top level - puzzles/2023 - Day17.cpp (source / functions) Coverage Total Hit
Test: master Lines: 98.3 % 59 58
Test Date: 2025-12-11 19:43:23 Functions: 100.0 % 7 7

            Line data    Source code
       1              : #include "Grid2d.h"
       2              : #include "LinewiseInput.h"
       3              : #include "PuzzleImpl.h"
       4              : 
       5              : #include <libassert/assert.hpp>
       6              : 
       7              : #include <limits>
       8              : #include <queue>
       9              : #include <string>
      10              : 
      11              : namespace {
      12              : 
      13              : using Coord = Grid2dSpan<uint8_t const>::Coord;
      14              : 
      15              : enum Dir : uint8_t { N = 0, E = 1, S = 2, W = 3 };
      16              : constexpr std::array<Dir, 4u> directions = {N, E, S, W};
      17              : constexpr std::array<Coord, 4u> stencil = {{{0, 1}, {1, 0}, {0, -1}, {-1, 0}}};
      18              : constexpr std::array<Dir, 4u> leftTurn = {W, N, E, S};
      19              : constexpr std::array<Dir, 4u> rightTurn = {E, S, W, N};
      20              : 
      21              : using NodePriority = std::tuple<unsigned, Dir, Coord>;
      22      3647352 : bool operator<(NodePriority const &lhs, NodePriority const &rhs) {
      23      3647352 :   return std::get<0>(lhs) > std::get<0>(rhs);
      24      3647352 : };
      25              : 
      26       275972 : unsigned costHeuristic(Coord start, Coord goal) {
      27       275972 :   return std::abs(start.x() - goal.x()) + std::abs(start.y() - goal.y());
      28       275972 : }
      29              : 
      30              : unsigned findShortestPath(Grid2dSpan<uint8_t const> heatLoss, Coord const &startPos,
      31              :                           Coord const &goalPos, int const minNumStepsSameDir,
      32            2 :                           int const maxNumStepsSameDir) {
      33              : 
      34            2 :   std::priority_queue<NodePriority> openSet;
      35            2 :   std::array<Grid2d<unsigned>, directions.size()> cost;
      36            2 :   for (auto &c : cost)
      37            8 :     c = Grid2d<unsigned>{heatLoss.xSize(), heatLoss.ySize(), std::numeric_limits<unsigned>::max()};
      38              : 
      39            8 :   for (Dir d : directions) {
      40            8 :     openSet.emplace(0, d, startPos);
      41            8 :     cost[d][startPos] = 0u;
      42            8 :   }
      43              : 
      44       261718 :   while (!openSet.empty()) {
      45       261718 :     auto [costEstimate, curDir, curPos] = openSet.top();
      46       261718 :     openSet.pop();
      47              : 
      48       261718 :     unsigned const curCost = cost[curDir][curPos];
      49              : 
      50       261718 :     if (curPos == goalPos)
      51            2 :       return curCost;
      52              : 
      53       261716 :     unsigned neighborCost = curCost;
      54       261716 :     Coord neighborPos = curPos;
      55      2058159 :     for (int steps = 1; steps <= maxNumStepsSameDir; ++steps) {
      56      1808103 :       neighborPos += stencil[curDir];
      57      1808103 :       if (neighborPos.x() < 0 || neighborPos.y() < 0 || neighborPos.x() >= heatLoss.xSize() ||
      58      1808103 :           neighborPos.y() >= heatLoss.ySize())
      59        11660 :         break;
      60              : 
      61      1796443 :       neighborCost += heatLoss[neighborPos];
      62              : 
      63      1796443 :       if (steps < minNumStepsSameDir)
      64       451665 :         continue;
      65              : 
      66      1344778 :       if (neighborCost < cost[leftTurn[curDir]][neighborPos]) {
      67       137986 :         cost[leftTurn[curDir]][neighborPos] = neighborCost;
      68       137986 :         openSet.emplace(neighborCost + costHeuristic(neighborPos, goalPos), leftTurn[curDir],
      69       137986 :                         neighborPos);
      70       137986 :       }
      71              : 
      72      1344778 :       if (neighborCost < cost[rightTurn[curDir]][neighborPos]) {
      73       137986 :         cost[rightTurn[curDir]][neighborPos] = neighborCost;
      74       137986 :         openSet.emplace(neighborCost + costHeuristic(neighborPos, goalPos), rightTurn[curDir],
      75       137986 :                         neighborPos);
      76       137986 :       }
      77      1344778 :     }
      78       261716 :   }
      79            2 :   PANIC();
      80            0 : }
      81              : 
      82              : } // namespace
      83              : 
      84            1 : template <> std::string solvePart1<2023, 17>(std::string_view const input) {
      85            1 :   LinewiseInput lines(input);
      86            1 :   Grid2d<char> grid = lines.makeCharGrid2d();
      87        19881 :   Grid2d<uint8_t> heatLoss = grid.map([](char const c) { return static_cast<uint8_t>(c - '0'); });
      88              : 
      89            1 :   return std::to_string(
      90            1 :       findShortestPath(heatLoss, {0, heatLoss.ySize() - 1}, {heatLoss.xSize() - 1, 0}, 1, 3));
      91            1 : }
      92              : 
      93            1 : template <> std::string solvePart2<2023, 17>(std::string_view const input) {
      94            1 :   LinewiseInput lines(input);
      95            1 :   Grid2d<char> grid = lines.makeCharGrid2d();
      96        19881 :   Grid2d<uint8_t> heatLoss = grid.map([](char const c) { return static_cast<uint8_t>(c - '0'); });
      97              : 
      98            1 :   return std::to_string(
      99            1 :       findShortestPath(heatLoss, {0, heatLoss.ySize() - 1}, {heatLoss.xSize() - 1, 0}, 4, 10));
     100            1 : }
        

Generated by: LCOV version 2.0-1