// // Created by Matthew Gretton-Dann on 12/12/2021. // #include #include #include #include #include #include #include enum class Register { a, b, c, d }; auto to_register(char c) -> Register { switch (c) { case 'a': return Register::a; case 'b': return Register::b; case 'c': return Register::c; case 'd': return Register::d; default: abort(); } } enum class Opcode { cpy, inc, dec, jnz, tgl, out }; auto to_opcode(std::string const& s) -> Opcode { if (s == "cpy") { return Opcode::cpy; } if (s == "inc") { return Opcode::inc; } if (s == "dec") { return Opcode::dec; } if (s == "jnz") { return Opcode::jnz; } if (s == "tgl") { return Opcode::tgl; } if (s == "out") { return Opcode::out; } abort(); } using Int = long; // NOLINT(google-runtime-int) using Operand = std::variant; struct Instruction { Instruction(Opcode opcode, Operand const& op1, Operand const& op2) : opcode_(opcode), op1_(op1), op2_(op2) { } [[nodiscard]] auto opcode() const noexcept -> Opcode { return opcode_; } [[nodiscard]] auto op1() const noexcept -> Operand const& { return op1_; } [[nodiscard]] auto op2() const noexcept -> Operand const& { return op2_; } void toggle() { switch (opcode_) { case Opcode::cpy: opcode_ = Opcode::jnz; break; case Opcode::jnz: opcode_ = Opcode::cpy; break; case Opcode::inc: opcode_ = Opcode::dec; break; case Opcode::dec: case Opcode::tgl: case Opcode::out: opcode_ = Opcode::inc; break; } } static auto instruction(std::string const& s) -> Instruction { Opcode opcode = to_opcode(s.substr(0, 3)); Operand op1{std::monostate()}; Operand op2{std::monostate()}; std::size_t idx{4}; { char* end{nullptr}; auto val{ std::strtol(s.data() + idx, // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) &end, 10)}; if (end != s.data() + idx) { // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) op1 = val; idx = end - s.data(); } else { op1 = to_register(s[idx]); idx += 1; } } if (idx < s.size()) { assert(s[idx] == ' '); ++idx; char* end{nullptr}; auto val{ std::strtol(s.data() + idx, // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) &end, 10)}; if (end != s.data() + idx) { // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) op2 = val; } else { op2 = to_register(s[idx]); } } return {opcode, op1, op2}; } private: Opcode opcode_; Operand op1_; Operand op2_; }; struct State { explicit State(std::vector instructions) : instructions_(std::move(instructions)) {} [[nodiscard]] auto reg(Register r) const noexcept -> Int { return registers_ [static_cast( // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) r)]; } void reg(Register r, Int v) noexcept { registers_[static_cast( // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) r)] = v; } void execute() { while (pc_ < instructions_.size()) { auto& i{instructions_[pc_]}; switch (i.opcode()) { case Opcode::cpy: set(i.op2(), value(i.op1())); break; case Opcode::inc: set(i.op1(), value(i.op1()) + 1); break; case Opcode::dec: set(i.op1(), value(i.op1()) - 1); break; case Opcode::jnz: if (value(i.op1()) != 0) { pc_ += value(i.op2()) - 1; } break; case Opcode::tgl: { auto dest{pc_ + value(i.op1())}; if (dest >= 0 && dest < instructions_.size()) { instructions_[dest].toggle(); } } break; case Opcode::out: std::cout << value(i.op1()) << '\n'; break; } ++pc_; } } private: auto value(Operand const& o) -> Int { if (std::holds_alternative(o)) { return registers_ [static_cast( // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) std::get(o))]; } if (std::holds_alternative(o)) { return std::get(o); } abort(); } void set(Operand const& dest, Int value) { if (std::holds_alternative(dest)) { registers_[ // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) static_cast(std::get(dest))] = value; } } std::vector instructions_; std::array registers_{0, 0, 0, 0}; Int pc_{0}; }; auto main() -> int { std::vector instructions; std::string line; while (std::getline(std::cin, line) && !line.empty()) { instructions.push_back(Instruction::instruction(line)); } State state(instructions); // So it looks as if the code we're given takes the value in register A adds 2548 to it and then // outputs the binary representation starting at the least significant bit. So we want // (a + 2548) to have the binary representation 1010101010 - which turns out to be 182. Int ra = 2730 - 2548; state.reg(Register::a, ra); state.execute(); }