#include namespace intcode { BadInstruction::BadInstruction(char const* what) : std::runtime_error{what} {} auto StepInput(Machine & m, ValueType input) -> void { std::get(Step(m)).pos = input; } auto StepOutput(Machine & m) -> ValueType { return std::get(Step(m)).val; } auto Step(Machine & m) -> std::variant { for (;;) { auto instruction = m.Next(); auto modes = instruction / 10; auto arg = [&]() -> ValueType & { auto &v = m.Next(); switch ((modes /= 10) % 10) { case 0: return m.At(v); case 1: return v; case 2: return m.Rel(v); default: throw BadInstruction{"invalid addressing mode"}; } }; switch (instruction % 100) { case 1: { arg() = arg() + arg(); break; } case 2: { arg() = arg() * arg(); break; } case 3: { return Input{arg()}; } case 4: { return Output{arg()}; } case 5: { auto a = arg(); auto b = arg(); if (a) { m.Goto(b); } break; } case 6: { auto a = arg(); auto b = arg(); if (!a) { m.Goto(b); } break; } case 7: { auto a = arg(); auto b = arg(); arg() = a < b; // order matters break; } case 8: { arg() = arg() == arg(); break; } case 9: m.Rebase(arg()); break; case 99: return Halt{}; default: throw BadInstruction{"invalid opcode"}; } } } } // namespace