AoC code coverage
Current view: top level - puzzles/2023 - Day06.cpp (source / functions) Coverage Total Hit
Test: master Lines: 96.2 % 53 51
Test Date: 2025-12-11 19:43:23 Functions: 100.0 % 5 5

            Line data    Source code
       1              : #include "LinewiseInput.h"
       2              : #include "PuzzleImpl.h"
       3              : 
       4              : #include <re2/re2.h>
       5              : 
       6              : #include <libassert/assert.hpp>
       7              : 
       8              : #include <cmath>
       9              : #include <cstdint>
      10              : #include <numeric>
      11              : #include <string>
      12              : #include <vector>
      13              : 
      14              : namespace {
      15              : 
      16              : struct Race {
      17              :   uint64_t time = 0u;
      18              :   uint64_t distance = 0u;
      19              : };
      20              : 
      21            1 : std::vector<Race> parseRaces(std::string_view timeStr, std::string_view distanceStr) {
      22            1 :   static RE2 const timePattern = "Time: +";
      23            1 :   static RE2 const distancePattern = "Distance: +";
      24            1 :   static RE2 const numberPattern = R"((\d+) *)";
      25            1 :   ASSUME(RE2::Consume(&timeStr, timePattern));
      26            1 :   ASSUME(RE2::Consume(&distanceStr, distancePattern));
      27              : 
      28            1 :   std::vector<Race> races;
      29            1 :   uint64_t time = 0;
      30            1 :   uint64_t distance = 0;
      31            5 :   while (RE2::Consume(&timeStr, numberPattern, &time)) {
      32            4 :     ASSUME(RE2::Consume(&distanceStr, numberPattern, &distance));
      33            4 :     races.push_back(Race{.time = time, .distance = distance});
      34            4 :   }
      35            1 :   return races;
      36            1 : }
      37              : 
      38            1 : Race parseSingleRace(std::string timeStr, std::string distanceStr) {
      39            1 :   static RE2 const timePattern = R"(Time:(\d+))";
      40            1 :   static RE2 const distancePattern = R"(Distance:(\d+))";
      41              : 
      42            1 :   std::erase(timeStr, ' ');
      43            1 :   std::erase(distanceStr, ' ');
      44              : 
      45            1 :   Race race;
      46            1 :   ASSUME(RE2::FullMatch(timeStr, timePattern, &race.time));
      47            1 :   ASSUME(RE2::FullMatch(distanceStr, distancePattern, &race.distance));
      48              : 
      49            1 :   return race;
      50            1 : }
      51              : 
      52            5 : uint64_t numPossibleRaces(Race const &race) {
      53            5 :   double const b = -static_cast<double>(race.time);
      54            5 :   double const c = static_cast<double>(race.distance); // NOLINT
      55              : 
      56            5 :   double const sqrtTerm = std::sqrt(b * b - 4.0 * c);
      57            5 :   double const x1 = (-b - sqrtTerm) * 0.5;
      58            5 :   double const x2 = (-b + sqrtTerm) * 0.5;
      59              : 
      60            5 :   DEBUG_ASSERT(!std::isnan(x1));
      61            5 :   DEBUG_ASSERT(!std::isnan(x2));
      62              : 
      63            5 :   uint64_t minChargeTime = std::ceil(x1);
      64            5 :   uint64_t maxChargeTime = std::floor(x2);
      65              : 
      66            5 :   uint64_t const distanceTravelled = (race.time - minChargeTime) * minChargeTime;
      67            5 :   if (distanceTravelled == race.distance)
      68            0 :     ++minChargeTime;
      69              : 
      70            5 :   if (distanceTravelled == race.distance)
      71            0 :     --maxChargeTime;
      72              : 
      73            5 :   return maxChargeTime - minChargeTime + 1u;
      74            5 : }
      75              : 
      76              : } // namespace
      77              : 
      78            1 : template <> std::string solvePart1<2023, 6>(std::string_view const input) {
      79            1 :   LinewiseInput const lines(input);
      80              : 
      81            1 :   std::vector<Race> const races = parseRaces(lines[0], lines[1]);
      82              : 
      83            1 :   return std::to_string(std::transform_reduce(races.begin(), races.end(), uint64_t(1),
      84            1 :                                               std::multiplies<>(), numPossibleRaces));
      85            1 : }
      86              : 
      87            1 : template <> std::string solvePart2<2023, 6>(std::string_view const input) {
      88            1 :   LinewiseInput const lines(input);
      89              : 
      90            1 :   Race race = parseSingleRace(std::string(lines[0]), std::string(lines[1]));
      91              : 
      92            1 :   return std::to_string(numPossibleRaces(race));
      93            1 : }
        

Generated by: LCOV version 2.0-1