#include "intcode.hpp" #include namespace intcode { BadInstruction::BadInstruction(std::size_t pc, value_type instruction) : pc{pc}, instruction{instruction} {} char const *BadInstruction::what() const noexcept { return "bad instruction"; } Machine::Machine() : rom_{}, ram_{}, pc_{0}, base_{0} {} Machine::Machine(std::vector ram) : rom_{ram}, ram_{}, pc_{0}, base_{0} {} auto Machine::ref(value_type instruction, value_type p, std::size_t offset) -> value_type & { 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{pc_, instruction}; } } auto Machine::at(std::size_t i) -> value_type & { return i < rom_.size() ? rom_[i] : ram_[i]; } auto Machine::step() -> std::variant { for (;;) { auto instruction = at(pc_); auto a = [=]() -> auto & { return ref(instruction, 100, 1); }; auto b = [=]() -> auto & { return ref(instruction, 1000, 2); }; auto c = [=]() -> auto & { 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{pc_, instruction}; } } } auto parse_stream(std::istream &in) -> std::vector { value_type x; std::string str; std::vector result; while (std::getline(in, str, ',')) { result.push_back(std::stoi(str)); } return result; } }