#include namespace intcode { BadInstruction::BadInstruction(char const* const what) : std::runtime_error{what} {} auto StepInput(Machine & m, ValueType const input) -> void { std::get(Step(m)).input = input; } auto StepOutput(Machine & m) -> ValueType { return std::get(Step(m)).output; } auto Step(Machine & m) -> std::variant { for (;;) { auto next = m.Next(); auto const instruction = next % 100; next /= 100; auto const arg = [&]() -> ValueType & { auto &v = m.Next(); auto const mode = next % 10; next /= 10; switch (mode) { case 0: return m.At(v); case 1: return v; case 2: return m.Rel(v); default: throw BadInstruction{"invalid addressing mode"}; } }; switch (instruction) { 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 const a = arg(); auto const b = arg(); if (a) { m.Goto(b); } break; } case 6: { auto const a = arg(); auto const b = arg(); if (!a) { m.Goto(b); } break; } case 7: { auto const a = arg(); arg() = a < arg(); break; } case 8: arg() = arg() == arg(); break; case 9: m.Rebase(arg()); break; case 99: return Halt{}; default: std::cout << instruction << std::endl; throw BadInstruction{"invalid opcode"}; } } } } // namespace