#include namespace intcode { BadInstruction::BadInstruction(char const* what) : std::runtime_error{what} {} 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: { auto a = arg(); auto b = arg(); auto& c = arg(); c = a + b; break; } case 2: { auto a = arg(); auto b = arg(); auto& c = arg(); c = a * b; 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(); auto& c = arg(); c = a < b; break; } case 8: { auto a = arg(); auto b = arg(); auto& c = arg(); c = a == b; break; } case 9: m.Rebase(arg()); break; case 99: return Halt{}; default: throw BadInstruction{"invalid opcode"}; } } } } // namespace