#include "intcode.hpp" #include intcode::intcode() : rom_{}, ram_{}, pc_{0}, base_{0} {} intcode::intcode(std::vector ram) : rom_{ram}, ram_{}, pc_{0}, base_{0} {} auto intcode::ref(std::int64_t instruction, std::int64_t p, std::size_t offset) -> std::int64_t& { auto& i = at(pc_ + offset); switch (instruction / p % 10) { case 0: return at(i); case 1: return i; case 2: return at(base_ + i); default: throw BadInstruction{instruction}; } } auto intcode::at(std::size_t i) -> std::int64_t& { return i < rom_.size() ? rom_[i] : ram_[i]; } auto intcode::step() -> std::variant { for (;;) { auto instruction = at(pc_); auto a = [this,instruction]() -> std::int64_t& { return ref(instruction, 100, 1); }; auto b = [this,instruction]() -> std::int64_t& { return ref(instruction, 1000, 2); }; auto c = [this,instruction]() -> std::int64_t& { return ref(instruction, 10000, 3); }; switch (instruction % 100) { case 1: c() = a() + b(); pc_ += 4; break; case 2: c() = a() * b(); pc_ += 4; break; case 3: { auto& pos = a(); pc_ += 2; return Input{pos}; } case 4: { auto val = a(); pc_ += 2; return Output{val}; } case 5: pc_ = a() ? b() : pc_ + 3; break; case 6: pc_ = a() ? pc_ + 3 : b(); break; case 7: c() = a() < b(); pc_ += 4; break; case 8: c() = a() == b(); pc_ += 4; break; case 9: base_ += a(); pc_ += 2; break; case 99: return Halt{}; default: throw BadInstruction{instruction}; } } } auto parse_stream(std::istream& in) -> std::vector { std::int64_t x; std::string str; std::vector result; while(std::getline(in, str, ',')) { result.push_back(std::stoi(str)); } return result; }