AoC code coverage
Current view: top level - puzzles/2024 - Day17.cpp (source / functions) Coverage Total Hit
Test: master Lines: 89.0 % 118 105
Test Date: 2025-07-28 10:53:57 Functions: 100.0 % 14 14

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

Generated by: LCOV version 2.0-1