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

Generated by: LCOV version 2.0-1