diff --git a/day02.cpp b/day02.cpp index 52f11b2..2156151 100644 --- a/day02.cpp +++ b/day02.cpp @@ -7,23 +7,23 @@ using namespace intcode; namespace { -auto compute(Machine machine, value_type x, value_type y) { - machine.at(1) = x; - machine.at(2) = y; - machine.step(); - return machine.at(0); +auto Compute(Machine machine, ValueType x, ValueType y) { + machine.At(1) = x; + machine.At(2) = y; + machine.Step(); + return machine.At(0); } } // namespace auto main() -> int { - auto machine = Machine{parse_stream(std::cin)}; + auto machine = Machine{ParseStream(std::cin)}; - std::cout << "Part 1: " << compute(machine, 12, 2) << std::endl; + std::cout << "Part 1: " << Compute(machine, 12, 2) << std::endl; for (std::int64_t i = 0; i < 100; i++) { for (std::int64_t j = 0; j < 100; j++) { - if (19690720 == compute(machine, i, j)) { + if (19690720 == Compute(machine, i, j)) { std::cout << "Part 2: " << 100 * i + j << std::endl; } } diff --git a/day05.cpp b/day05.cpp index 8e7ebe9..d79dad9 100644 --- a/day05.cpp +++ b/day05.cpp @@ -6,8 +6,8 @@ using namespace intcode; namespace { -auto compute(Machine machine, value_type d) -> value_type { - value_type last_output = -1; +auto Compute(Machine machine, ValueType d) -> ValueType { + ValueType last_output = -1; while (std::visit(overloaded{ [](Halt) { return false; }, [d, &machine](Input arg) { @@ -18,14 +18,14 @@ auto compute(Machine machine, value_type d) -> value_type { last_output = arg.val; return true; }}, - machine.step())); + machine.Step())); return last_output; } } // namespace auto main() -> int { - auto machine = Machine{parse_stream(std::cin)}; - std::cout << "Part 1: " << compute(machine, 1) << std::endl; - std::cout << "Part 2: " << compute(std::move(machine), 5) << std::endl; + auto machine = Machine{ParseStream(std::cin)}; + std::cout << "Part 1: " << Compute(machine, 1) << std::endl; + std::cout << "Part 2: " << Compute(std::move(machine), 5) << std::endl; } diff --git a/day07.cpp b/day07.cpp index caab2f6..ea9c230 100644 --- a/day07.cpp +++ b/day07.cpp @@ -10,18 +10,18 @@ using namespace intcode; namespace { -template auto set_params(Machine machine, R const ¶ms) { +template auto Controller(Machine machine, R const ¶ms) { std::vector amps; for (auto p : params) { auto m = machine; - std::get(m.step()).pos = p; + std::get(m.Step()).pos = p; amps.push_back(std::move(m)); } return amps; } template -auto feed(R &&s, value_type start) -> std::optional { +auto Feed(R &&s, ValueType start) -> std::optional { for (auto &m : amps) { auto i = m.step(); if (auto p = std::get_if(&i)) { @@ -34,23 +34,23 @@ auto feed(R &&s, value_type start) -> std::optional { return {start}; } -auto compute1(Machine machine, std::vector const ¶ms) - -> value_type { - return *feed(set_params(std::move(machine), params), 0); +auto compute1(Machine machine, std::vector const ¶ms) + -> ValueType { + return *Feed(Controller(std::move(machine), params), 0); } -auto compute2(Machine machine, std::vector const ¶ms) - -> value_type { - auto amps = set_params(std::move(machine), params); - value_type last = 0; - while (auto next = feed(amps, last)) { +auto compute2(Machine machine, std::vector const ¶ms) + -> ValueType { + auto amps = Controller(std::move(machine), params); + ValueType last = 0; + while (auto next = Feed(amps, last)) { last = *next; } return last; } -template const &> F> -auto optimize(Machine machine, std::vector params, F f) { - value_type best = 0; +template const &> F> +auto optimize(Machine machine, std::vector params, F f) { + ValueType best = 0; do { best = std::max(best, f(machine, params)); } while (std::next_permutation(params.begin(), params.end())); @@ -60,7 +60,7 @@ auto optimize(Machine machine, std::vector params, F f) { } // namespace auto main() -> int { - auto machine = Machine{parse_stream(std::cin)}; + auto machine = Machine{ParseStream(std::cin)}; std::cout << "Part 1: " << optimize(machine, {0, 1, 2, 3, 4}, compute1) << std::endl; std::cout << "Part 2: " << optimize(std::move(machine), {5, 6, 7, 8, 9}, compute2) << std::endl; } diff --git a/day09.cpp b/day09.cpp index a66cd2e..bcdc80b 100644 --- a/day09.cpp +++ b/day09.cpp @@ -6,8 +6,8 @@ using namespace intcode; namespace { -auto compute(Machine machine, value_type d) -> value_type { - value_type output = -1; +auto Compute(Machine machine, ValueType d) -> ValueType { + ValueType output = -1; while (std::visit(overloaded{ [](Halt) { return false; }, [d](Input arg) { @@ -18,14 +18,14 @@ auto compute(Machine machine, value_type d) -> value_type { output = arg.val; return false; }}, - machine.step())); + machine.Step())); return output; } } // namespace auto main() -> int { - auto machine = Machine{parse_stream(std::cin)}; - std::cout << "Part 1: " << compute(machine, 1) << std::endl; - std::cout << "Part 2: " << compute(std::move(machine), 2) << std::endl; + auto machine = Machine{ParseStream(std::cin)}; + std::cout << "Part 1: " << Compute(machine, 1) << std::endl; + std::cout << "Part 2: " << Compute(std::move(machine), 2) << std::endl; } diff --git a/lib/include/intcode.hpp b/lib/include/intcode.hpp index f0c01b8..1e12e95 100644 --- a/lib/include/intcode.hpp +++ b/lib/include/intcode.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -13,43 +14,47 @@ template overloaded(Ts...) -> overloaded; namespace intcode { - using value_type = std::int64_t; + using ValueType = std::int64_t; struct Input { - value_type &pos; + ValueType &pos; }; struct Output { - value_type val; + ValueType val; }; struct Halt {}; class Machine { - std::vector rom_; - std::unordered_map ram_; + std::vector rom_; + std::unordered_map ram_; std::size_t pc_; std::size_t base_; - auto ref(value_type instruction, value_type p, std::size_t offset) - -> value_type &; - public: Machine(); - explicit Machine(std::vector ram); - auto step() -> std::variant; - auto at(std::size_t) -> value_type &; + explicit Machine(std::vector ram); + /// Advance machine until next side effect + auto Step() -> std::variant; + + /// Access memory at absolute address + /// @param address + /// @return reference to memory at given address + auto At(std::size_t address) -> ValueType &; + + /// Access memory at address relative to base pointer + /// @param offset from base pointer + /// @return reference to memory at given offset + auto Rel(std::size_t offset) -> ValueType &; }; -struct BadInstruction : public std::exception { - std::size_t pc; - value_type instruction; - explicit BadInstruction(std::size_t pc, value_type instruction); - const char *what() const noexcept override; +struct BadInstruction : public std::runtime_error { + explicit BadInstruction(char const* what); }; -auto parse_stream(std::istream &in) -> std::vector; +auto ParseStream(std::istream &in) -> std::vector; } diff --git a/lib/intcode.cpp b/lib/intcode.cpp index 4bb5b2e..d98c30a 100644 --- a/lib/intcode.cpp +++ b/lib/intcode.cpp @@ -3,41 +3,45 @@ namespace intcode { -BadInstruction::BadInstruction(std::size_t pc, value_type instruction) - : pc{pc}, instruction{instruction} {} - -char const *BadInstruction::what() const noexcept { return "bad instruction"; } +BadInstruction::BadInstruction(char const* what) + : std::runtime_error{what} {} Machine::Machine() : rom_{}, ram_{}, pc_{0}, base_{0} {} -Machine::Machine(std::vector ram) +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); +namespace { +auto Ref(Machine & m, ValueType instruction, std::size_t k, ValueType p) + -> ValueType & { + auto &v = m.At(k); switch (instruction / p % 10) { case 0: - return at(i); + return m.At(v); case 1: - return i; + return v; case 2: - return at(base_ + i); + return m.At(m.Rel(v)); default: - throw BadInstruction{pc_, instruction}; + throw BadInstruction{"invalid addressing mode"}; } } +} -auto Machine::at(std::size_t i) -> value_type & { +auto Machine::At(std::size_t i) -> ValueType & { return i < rom_.size() ? rom_[i] : ram_[i]; } -auto Machine::step() -> std::variant { +auto Machine::Rel(std::size_t i) -> ValueType & { + return At(base_ + 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); }; + auto instruction = At(pc_); + auto a = [=]() -> auto & { return Ref(*this, instruction, pc_+1, 100); }; + auto b = [=]() -> auto & { return Ref(*this, instruction, pc_+2, 1000); }; + auto c = [=]() -> auto & { return Ref(*this, instruction, pc_+3, 10000); }; switch (instruction % 100) { case 1: @@ -89,15 +93,15 @@ auto Machine::step() -> std::variant { return Halt{}; default: - throw BadInstruction{pc_, instruction}; + throw BadInstruction{"invalid opcode"}; } } } -auto parse_stream(std::istream &in) -> std::vector { - value_type x; +auto ParseStream(std::istream &in) -> std::vector { + ValueType x; std::string str; - std::vector result; + std::vector result; while (std::getline(in, str, ',')) { result.push_back(std::stoi(str)); }