AoC code coverage
Current view: top level - puzzles/2024 - Day17.cpp (source / functions) Coverage Total Hit
Test: master Lines: 88.8 % 116 103
Test Date: 2025-12-11 19:43:23 Functions: 100.0 % 12 12

            Line data    Source code
       1              : #include "PuzzleImpl.h"
       2              : 
       3              : #include "Parsing.h"
       4              : #include "Views.h"
       5              : 
       6              : #include <re2/re2.h>
       7              : 
       8              : #include <algorithm>
       9              : #include <cstddef>
      10              : #include <ranges>
      11              : #include <string_view>
      12              : 
      13              : using namespace std::literals;
      14              : 
      15              : namespace {
      16              : 
      17              : class Computer {
      18              : public:
      19              :   Computer(uint64_t const a, uint64_t const b, uint64_t const c,
      20              :            std::vector<uint64_t> const &program)
      21            2 :       : _a(a), _b(b), _c(c), _program(program) {}
      22              : 
      23          155 :   [[nodiscard]] auto const &output() const { return _output; }
      24           74 :   [[nodiscard]] auto const &program() const { return _program; }
      25              : 
      26            1 :   std::vector<uint64_t> const &run() { return run(_a); }
      27              : 
      28          154 :   std::vector<uint64_t> const &run(uint64_t const a) {
      29          154 :     _a = a;
      30          154 :     _ip = 0;
      31          154 :     _output.clear();
      32        11818 :     while (_ip < _program.size())
      33        11664 :       step();
      34              : 
      35          154 :     return output();
      36          154 :   }
      37              : 
      38              : private:
      39        11664 :   uint64_t op() {
      40        11664 :     ASSUME(_ip < _program.size());
      41        11664 :     return _program[_ip];
      42        11664 :   }
      43              : 
      44        11664 :   void step() {
      45        11664 :     switch (op()) {
      46         1458 :     case 0: // adv
      47         1458 :       _a >>= comboOperand();
      48         1458 :       _ip += 2;
      49         1458 :       break;
      50         2916 :     case 1: // bxl
      51         2916 :       _b ^= literalOperand();
      52         2916 :       _ip += 2;
      53         2916 :       break;
      54         1458 :     case 2: // bst
      55         1458 :       _b = comboOperand() % 8u;
      56         1458 :       _ip += 2;
      57         1458 :       break;
      58         1458 :     case 3: // jnz
      59         1458 :       if (_a == 0)
      60          154 :         _ip += 2;
      61         1304 :       else
      62         1304 :         _ip = literalOperand();
      63         1458 :       break;
      64         1458 :     case 4: // bxc
      65         1458 :       _b ^= _c;
      66         1458 :       _ip += 2;
      67         1458 :       break;
      68         1458 :     case 5: // out
      69         1458 :       _output.push_back(comboOperand() % 8u);
      70         1458 :       _ip += 2;
      71         1458 :       break;
      72            0 :     case 6: // bdv
      73            0 :       _b = _a >> comboOperand();
      74            0 :       _ip += 2;
      75            0 :       break;
      76         1458 :     case 7: // cdv
      77         1458 :       _c = _a >> comboOperand();
      78         1458 :       _ip += 2;
      79         1458 :       break;
      80            0 :     default:
      81            0 :       UNREACHABLE(op());
      82        11664 :     }
      83        11664 :   }
      84              : 
      85         4220 :   uint64_t literalOperand() {
      86         4220 :     ASSUME(_ip + 1u < _program.size());
      87         4220 :     return _program[_ip + 1u];
      88         4220 :   }
      89              : 
      90         5832 :   uint64_t comboOperand() {
      91         5832 :     ASSUME(_ip + 1u < _program.size());
      92         5832 :     uint64_t const val = _program[_ip + 1u];
      93         5832 :     switch (val) {
      94            0 :     case 0:
      95            0 :     case 1:
      96            0 :     case 2:
      97         1458 :     case 3:
      98         1458 :       return val;
      99         1458 :     case 4:
     100         1458 :       return _a;
     101         2916 :     case 5:
     102         2916 :       return _b;
     103            0 :     case 6:
     104            0 :       return _c;
     105            0 :     default:
     106            0 :       UNREACHABLE(val);
     107         5832 :     }
     108         5832 :   }
     109              : 
     110              :   uint64_t _a = 0;
     111              :   uint64_t _b = 0;
     112              :   uint64_t _c = 0;
     113              :   uint64_t _ip = 0;
     114              :   std::vector<uint64_t> _program;
     115              :   std::vector<uint64_t> _output;
     116              : };
     117              : 
     118            2 : Computer parse(std::string_view const input) {
     119            2 :   RE2 regex =
     120            2 :       R"(Register A: (\d+)\nRegister B: (\d+)\nRegister C: (\d+)\n\nProgram: ((?:\d+,)*\d+))"sv;
     121              : 
     122            2 :   uint64_t a = 0;
     123            2 :   uint64_t b = 0;
     124            2 :   uint64_t c = 0;
     125            2 :   std::string_view programStr;
     126              : 
     127            2 :   RE2::FullMatch(input, regex, &a, &b, &c, &programStr);
     128              : 
     129            2 :   return {a, b, c, parseIntegerRange<uint64_t>(programStr)};
     130            2 : }
     131              : 
     132              : } // namespace
     133              : 
     134            1 : template <> std::string solvePart1<2024, 17>(std::string_view const input) {
     135            1 :   Computer c = parse(input);
     136            1 :   c.run();
     137              : 
     138            1 :   return c.output() | views::toStringAndJoinWith(",") | std::ranges::to<std::string>();
     139            1 : }
     140              : 
     141            1 : template <> std::string solvePart2<2024, 17>(std::string_view const input) {
     142            1 :   Computer c = parse(input);
     143              : 
     144            1 :   uint64_t a = 0;
     145           37 :   for (auto it = c.program().rbegin(); it != c.program().rend();) {
     146           36 :     uint64_t i = a & 0b111;
     147          163 :     for (; i < 8u; ++i, ++a) {
     148          153 :       if (c.run(a).front() == *it) {
     149           26 :         break;
     150           26 :       }
     151          153 :     }
     152           36 :     if (i < 8u) {
     153           26 :       ++it;
     154           26 :       if (it != c.program().rend())
     155           25 :         a <<= 3u;
     156           26 :     } else {
     157           10 :       ASSUME(it != c.program().rbegin());
     158           10 :       --it;
     159           10 :       a >>= 3u;
     160           10 :     }
     161           36 :   }
     162              : 
     163            1 :   return std::to_string(a);
     164            1 : }
        

Generated by: LCOV version 2.0-1