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

Generated by: LCOV version 2.0-1