AoC code coverage
Current view: top level - puzzles/2023 - Day05.cpp (source / functions) Coverage Total Hit
Test: master Lines: 98.0 % 102 100
Test Date: 2025-07-28 10:53:57 Functions: 100.0 % 13 13

            Line data    Source code
       1              : #include "IntegerCast.h"
       2              : #include "LinewiseInput.h"
       3              : #include "Parsing.h"
       4              : #include "PuzzleImpl.h"
       5              : 
       6              : #include <libassert/assert.hpp>
       7              : #include <re2/re2.h>
       8              : 
       9              : #include <algorithm>
      10              : #include <cstdint>
      11              : #include <vector>
      12              : 
      13              : namespace {
      14              : 
      15              : // interval [begin, end)
      16              : struct ValueRange {
      17              :   uint64_t begin = 0;
      18              :   uint64_t end = 0;
      19              : };
      20              : 
      21              : class Map {
      22              : public:
      23           14 :   Map(auto begin, auto end) {
      24           14 :     static RE2 const headerPattern = R"((\w+)-to-(\w+) map:)";
      25           14 :     ASSUME(RE2::FullMatch(*begin, headerPattern, &_srcCategory, &_dstCategory));
      26           14 :     _ranges.assign(std::next(begin), end);
      27         5428 :     std::ranges::sort(_ranges, std::ranges::less{}, [](auto const &r) { return r.src.begin; });
      28           14 :   }
      29              : 
      30          140 :   uint64_t operator()(uint64_t const i) const {
      31          140 :     auto it = std::ranges::upper_bound(_ranges, i, std::ranges::less{},
      32          721 :                                        [](auto const &r) { return r.src.end; });
      33          140 :     if (it < _ranges.end() && i >= it->src.begin) {
      34          134 :       return i + it->offset;
      35          134 :     } else {
      36            6 :       return i;
      37            6 :     }
      38          140 :   }
      39              : 
      40          681 :   void operator()(ValueRange const r, auto out) const {
      41         1103 :     for (uint64_t i = r.begin; i < r.end;) {
      42         1067 :       auto it = std::upper_bound(_ranges.begin(), _ranges.end(), i,
      43         5734 :                                  [](uint64_t const x, Range const &r) { return x < r.src.end; });
      44         1067 :       if (it == _ranges.end()) {
      45            0 :         out++ = ValueRange(i, r.end);
      46            0 :         break;
      47         1067 :       } else if (i >= it->src.begin) {
      48         1021 :         if (r.end <= it->src.end) {
      49          645 :           out++ = ValueRange(i + it->offset, r.end + it->offset);
      50          645 :           break;
      51          645 :         } else {
      52          376 :           out++ = ValueRange(i + it->offset, it->src.end + it->offset);
      53          376 :           i = it->src.end;
      54          376 :         }
      55         1021 :       } else {
      56           46 :         out++ = ValueRange(i, it->src.begin);
      57           46 :         i = it->src.begin;
      58           46 :       }
      59         1067 :     }
      60          681 :   }
      61              : 
      62              : private:
      63              :   struct Range {
      64          464 :     Range(std::string_view const s) {
      65          464 :       static RE2 const rangePattern = R"((\d+) (\d+) (\d+))";
      66          464 :       uint64_t dstStart = 0;
      67          464 :       uint64_t size = 0;
      68          464 :       ASSUME(RE2::FullMatch(s, rangePattern, &dstStart, &src.begin, &size));
      69          464 :       src.end = src.begin + size;
      70          464 :       offset = integerCast<int64_t>(dstStart) - integerCast<int64_t>(src.begin);
      71          464 :     }
      72              : 
      73              :     ValueRange src;
      74              :     int64_t offset = 0;
      75              :   };
      76              : 
      77              :   std::string _srcCategory;
      78              :   std::string _dstCategory;
      79              :   std::vector<Range> _ranges;
      80              : };
      81              : 
      82            1 : std::vector<uint64_t> parseSeeds(std::string_view s) {
      83            1 :   ASSUME(RE2::Consume(&s, "seeds: "));
      84            1 :   s.remove_prefix(s.find(':') + 1u);
      85            1 :   return parseRange<uint64_t>(s);
      86            1 : }
      87              : 
      88            1 : std::vector<ValueRange> parseSeedRanges(std::string_view s) {
      89            1 :   static RE2 const numberPattern = R"((\d+) (\d+) ?)";
      90              : 
      91            1 :   ASSUME(RE2::Consume(&s, "seeds: "));
      92            1 :   std::vector<ValueRange> seeds;
      93            1 :   ValueRange seedRange;
      94            1 :   uint64_t size = 0;
      95           11 :   while (RE2::Consume(&s, numberPattern, &seedRange.begin, &size)) {
      96           10 :     seedRange.end = seedRange.begin + size;
      97           10 :     seeds.push_back(seedRange);
      98           10 :   }
      99            1 :   return seeds;
     100            1 : }
     101              : 
     102            2 : std::vector<Map> parseMaps(auto begin, auto end) {
     103            2 :   std::vector<Map> maps;
     104              : 
     105           30 :   for (auto it = begin; it != end;) {
     106           28 :     if (it->empty()) {
     107           14 :       ++it;
     108           14 :       continue;
     109           14 :     }
     110           14 :     auto rangeBegin = it;
     111          476 :     it = std::find_if(std::next(it), end, [](std::string_view s) { return s.empty(); });
     112           14 :     maps.emplace_back(rangeBegin, it);
     113           14 :   }
     114              : 
     115            2 :   return maps;
     116            2 : }
     117              : } // namespace
     118              : 
     119            1 : template <> size_t part1<2023, 5>(std::string_view const input) {
     120            1 :   LinewiseInput const lines(input);
     121              : 
     122            1 :   auto it = lines.begin();
     123            1 :   std::vector<uint64_t> seeds = parseSeeds(*it++);
     124            1 :   std::vector<Map> maps = parseMaps(it, lines.end());
     125              : 
     126            1 :   std::vector<ValueRange> tmp;
     127            7 :   for (auto const &map : maps) {
     128            7 :     std::ranges::transform(seeds, seeds.begin(), map);
     129            7 :   }
     130              : 
     131            1 :   return *std::ranges::min_element(seeds);
     132            1 : }
     133              : 
     134            1 : template <> size_t part2<2023, 5>(std::string_view const input) {
     135            1 :   LinewiseInput const lines(input);
     136              : 
     137            1 :   auto it = lines.begin();
     138            1 :   std::vector<ValueRange> seedRanges = parseSeedRanges(*it++);
     139            1 :   std::vector<Map> maps = parseMaps(it, lines.end());
     140              : 
     141            1 :   std::vector<ValueRange> tmp;
     142            7 :   for (auto const &map : maps) {
     143            7 :     tmp.reserve(seedRanges.size() * 2u);
     144          681 :     for (auto const &seedRange : seedRanges) {
     145          681 :       map(seedRange, std::back_inserter(tmp));
     146          681 :     }
     147            7 :     seedRanges.swap(tmp);
     148            7 :     tmp.clear();
     149            7 :   }
     150              : 
     151            1 :   auto minIt = std::ranges::min_element(seedRanges, std::ranges::less{}, &ValueRange::begin);
     152              : 
     153            1 :   return minIt->begin;
     154            1 : }
        

Generated by: LCOV version 2.0-1