diff --git a/2019/src/day07.cpp b/2019/src/day07.cpp index 341e85a..b638c0d 100644 --- a/2019/src/day07.cpp +++ b/2019/src/day07.cpp @@ -5,127 +5,7 @@ #include "utils.hpp" namespace { - class IntCodeComputer { - public: - explicit IntCodeComputer(std::vector program, std::deque initial_inputs) : - program{std::move(program)}, inputs{std::move(initial_inputs)} { - } - - void run() { - while (ip < program.size()) { - switch (program[ip] % 100) { - case 1: - program[program[ip + 3]] = interpret_value(1) + interpret_value(2); - ip += 4; - break; - - case 2: - program[program[ip + 3]] = interpret_value(1) * interpret_value(2); - ip += 4; - break; - - case 3: - if (inputs.empty()) { - return; - } - - program[program[ip + 1]] = inputs.front(); - inputs.pop_front(); - ip += 2; - break; - - case 4: - outputSink->sendInput(interpret_value(1)); - ip += 2; - break; - - case 5: // Jump if non-zero - if (interpret_value(1)) { - ip = interpret_value(2); - } else { - ip += 3; - } - break; - - case 6: // Jump if zero - if (!interpret_value(1)) { - ip = interpret_value(2); - } else { - ip += 3; - } - break; - - case 7: // equality - program[program[ip + 3]] = interpret_value(1) < interpret_value(2); - ip += 4; - break; - - case 8: // less than - program[program[ip + 3]] = interpret_value(1) == interpret_value(2) ? 1 : 0; - ip += 4; - break; - - case 99: - halted = true; - return; - - default: - char buffer[30]; - std::snprintf(buffer, sizeof(buffer), "Invalid opcode: %d", program[ip]); - - throw std::domain_error(buffer); - } - } - } - - void sendInput(int input) { - inputs.push_back(input); - } - - void connectOutput(IntCodeComputer &computer) { - outputSink = &computer; - } - - [[nodiscard]] bool isTerminated() const { - return halted; - } - - [[nodiscard]] const std::deque ¤tInputs() const { - return inputs; - } - - private: - std::vector program; - std::deque inputs = {}; - IntCodeComputer *outputSink = nullptr; - int ip = 0; - bool halted = false; - - [[nodiscard]] int interpret_value(int pos) const { - bool immediate; - switch (pos) { - case 1: - immediate = program[ip] / 100 % 10; - break; - case 2: - immediate = program[ip] / 1000 % 10; - break; - - case 3: - immediate = program[ip] / 10000 % 10; - break; - - default: - throw std::out_of_range("Invalid position"); - } - - if (immediate) { - return program[ip + pos]; - } else { - return program[program[ip + pos]]; - } - } - }; + using aoc2019::IntCodeComputer; int simulate(const std::vector &program, const std::array &phases) { int state = 0; @@ -138,10 +18,10 @@ namespace { return state; } - int simulate2(const std::vector &program, const std::array &phases) { + int simulate2(const std::vector &program, const std::array &phases) { std::vector computers; for (int phase : phases) { - computers.emplace_back(program, std::deque{phase}); + computers.emplace_back(program, std::deque{phase}); } for (int i = 0; i < computers.size(); ++i) { @@ -174,7 +54,7 @@ void aoc2019::day07_part1(std::istream &input, std::ostream &output) { } void aoc2019::day07_part2(std::istream &input, std::ostream &output) { - const auto program = aoc2019::read_intcode(input); + const auto program = aoc2019::IntCodeComputer::read_intcode(input); std::array phases{5, 6, 7, 8, 9}; int best = 0; diff --git a/2019/src/day09.cpp b/2019/src/day09.cpp index 28f8285..58c04da 100644 --- a/2019/src/day09.cpp +++ b/2019/src/day09.cpp @@ -1,10 +1,35 @@ #include +#include #include "days.hpp" +#include "utils.hpp" void aoc2019::day09_part1(std::istream &input, std::ostream &output) { - output << "Not implemented\n"; + auto program = IntCodeComputer::read_intcode(input); + std::deque outputs; + + IntCodeComputer computer(std::move(program), { 1 }); + computer.connectOutput(outputs); + + computer.run(); + + if (outputs.size() != 1) { + std::cerr << "Error: " << outputs.size() << std::endl; + for (auto c : outputs) { + std::cerr << c << std::endl; + } + } else { + output << outputs.front() << std::endl; + } } void aoc2019::day09_part2(std::istream &input, std::ostream &output) { - output << "Not implemented\n"; + auto program = IntCodeComputer::read_intcode(input); + std::deque outputs; + + IntCodeComputer computer(std::move(program), { 2 }); + computer.connectOutput(outputs); + + computer.run(); + + output << outputs.front() << std::endl; } diff --git a/2019/src/utils.cpp b/2019/src/utils.cpp index af395fc..5db9c68 100644 --- a/2019/src/utils.cpp +++ b/2019/src/utils.cpp @@ -113,3 +113,152 @@ std::vector aoc2019::read_intcode(std::istream &input) { return program; } + +aoc2019::IntCodeComputer::value_t &aoc2019::IntCodeComputer::interpret_value(int pos) { + value_t immediate; + switch (pos) { + case 1: + immediate = program[ip] / 100 % 10; + break; + case 2: + immediate = program[ip] / 1000 % 10; + break; + + case 3: + immediate = program[ip] / 10000 % 10; + break; + + default: + throw std::out_of_range("Invalid position"); + } + + value_t index; + + switch (immediate) { + case 0: + index = program[ip + pos]; + break; + + case 1: + index = ip + pos; + break; + + case 2: + index = program[ip + pos] + relative; + break; + + default: + throw std::out_of_range("Invalid mode"); + } + + if (program.size() <= index) { + program.resize(index + 1); + } + + return program[index]; +} + +void aoc2019::IntCodeComputer::connectOutput(aoc2019::IntCodeComputer &computer) { + outputSink = &computer.inputs; +} + +void aoc2019::IntCodeComputer::connectOutput(std::deque &sink) { + outputSink = &sink; +} + +bool aoc2019::IntCodeComputer::isTerminated() const { + return halted; +} + +const std::deque &aoc2019::IntCodeComputer::currentInputs() const { + return inputs; +} + +std::vector aoc2019::IntCodeComputer::read_intcode(std::istream &input) { + std::vector program; + for (value_t current; input >> current; input.ignore()) { + program.push_back(current); + } + + return program; +} + +void aoc2019::IntCodeComputer::run() { + while (ip < program.size()) { + switch (program[ip] % 100) { + case 1: + interpret_value(3) = interpret_value(1) + interpret_value(2); + ip += 4; + break; + + case 2: + interpret_value(3) = interpret_value(1) * interpret_value(2); + ip += 4; + break; + + case 3: + if (inputs.empty()) { + return; + } + + interpret_value(1) = inputs.front(); + inputs.pop_front(); + ip += 2; + break; + + case 4: + outputSink->push_back(interpret_value(1)); + ip += 2; + break; + + case 5: // Jump if non-zero + if (interpret_value(1)) { + ip = interpret_value(2); + } else { + ip += 3; + } + break; + + case 6: // Jump if zero + if (!interpret_value(1)) { + ip = interpret_value(2); + } else { + ip += 3; + } + break; + + case 7: // equality + interpret_value(3) = interpret_value(1) < interpret_value(2); + ip += 4; + break; + + case 8: // less than + interpret_value(3) = interpret_value(1) == interpret_value(2) ? 1 : 0; + ip += 4; + break; + + case 9: + relative += interpret_value(1); + ip += 2; + break; + + case 99: + halted = true; + return; + + default: + char buffer[30]; + std::snprintf(buffer, sizeof(buffer), "Invalid opcode: %d", program[ip]); + + throw std::domain_error(buffer); + } + } +} + +aoc2019::IntCodeComputer::IntCodeComputer(std::vector program, std::deque initial_inputs) : + program{std::move(program)}, inputs{std::move(initial_inputs)} { +} + +void aoc2019::IntCodeComputer::sendInput(aoc2019::IntCodeComputer::value_t input) { + inputs.push_back(input); +} diff --git a/2019/src/utils.hpp b/2019/src/utils.hpp index 44e6707..7ae5f2b 100644 --- a/2019/src/utils.hpp +++ b/2019/src/utils.hpp @@ -26,4 +26,32 @@ namespace aoc2019 { std::vector read_intcode(std::istream &input); std::vector run_intcode(std::vector &program, std::deque inputs = {}); + + class IntCodeComputer { + public: + typedef std::int64_t value_t; + + explicit IntCodeComputer(std::vector program, std::deque initial_inputs = {}); + + void run(); + void connectOutput(IntCodeComputer &computer); + void connectOutput(std::deque &sink); + void sendInput(value_t input); + + [[nodiscard]] bool isTerminated() const; + + [[nodiscard]] const std::deque ¤tInputs() const; + + static std::vector read_intcode(std::istream &input); + + private: + std::vector program; + std::deque inputs = {}; + std::deque *outputSink = nullptr; + int ip = 0; + int relative = 0; + bool halted = false; + + [[nodiscard]] value_t &interpret_value(int pos); + }; }