mirror of
https://github.com/bertptrs/adventofcode.git
synced 2025-12-27 05:40:32 +01:00
Implement day 9.
This commit is contained in:
@@ -5,127 +5,7 @@
|
|||||||
#include "utils.hpp"
|
#include "utils.hpp"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
class IntCodeComputer {
|
using aoc2019::IntCodeComputer;
|
||||||
public:
|
|
||||||
explicit IntCodeComputer(std::vector<int> program, std::deque<int> 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<int> ¤tInputs() const {
|
|
||||||
return inputs;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<int> program;
|
|
||||||
std::deque<int> 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]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
int simulate(const std::vector<int> &program, const std::array<int, 5> &phases) {
|
int simulate(const std::vector<int> &program, const std::array<int, 5> &phases) {
|
||||||
int state = 0;
|
int state = 0;
|
||||||
@@ -138,10 +18,10 @@ namespace {
|
|||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
int simulate2(const std::vector<int> &program, const std::array<int, 5> &phases) {
|
int simulate2(const std::vector<std::int64_t> &program, const std::array<int, 5> &phases) {
|
||||||
std::vector<IntCodeComputer> computers;
|
std::vector<IntCodeComputer> computers;
|
||||||
for (int phase : phases) {
|
for (int phase : phases) {
|
||||||
computers.emplace_back(program, std::deque<int>{phase});
|
computers.emplace_back(program, std::deque<int64_t>{phase});
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < computers.size(); ++i) {
|
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) {
|
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<int, 5> phases{5, 6, 7, 8, 9};
|
std::array<int, 5> phases{5, 6, 7, 8, 9};
|
||||||
|
|
||||||
int best = 0;
|
int best = 0;
|
||||||
|
|||||||
@@ -1,10 +1,35 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <deque>
|
||||||
#include "days.hpp"
|
#include "days.hpp"
|
||||||
|
#include "utils.hpp"
|
||||||
|
|
||||||
void aoc2019::day09_part1(std::istream &input, std::ostream &output) {
|
void aoc2019::day09_part1(std::istream &input, std::ostream &output) {
|
||||||
output << "Not implemented\n";
|
auto program = IntCodeComputer::read_intcode(input);
|
||||||
|
std::deque<std::int64_t> 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) {
|
void aoc2019::day09_part2(std::istream &input, std::ostream &output) {
|
||||||
output << "Not implemented\n";
|
auto program = IntCodeComputer::read_intcode(input);
|
||||||
|
std::deque<std::int64_t> outputs;
|
||||||
|
|
||||||
|
IntCodeComputer computer(std::move(program), { 2 });
|
||||||
|
computer.connectOutput(outputs);
|
||||||
|
|
||||||
|
computer.run();
|
||||||
|
|
||||||
|
output << outputs.front() << std::endl;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,3 +113,152 @@ std::vector<int> aoc2019::read_intcode(std::istream &input) {
|
|||||||
|
|
||||||
return program;
|
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<value_t> &sink) {
|
||||||
|
outputSink = &sink;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool aoc2019::IntCodeComputer::isTerminated() const {
|
||||||
|
return halted;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::deque<aoc2019::IntCodeComputer::value_t> &aoc2019::IntCodeComputer::currentInputs() const {
|
||||||
|
return inputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<aoc2019::IntCodeComputer::value_t> aoc2019::IntCodeComputer::read_intcode(std::istream &input) {
|
||||||
|
std::vector<value_t> 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<value_t> program, std::deque<value_t> initial_inputs) :
|
||||||
|
program{std::move(program)}, inputs{std::move(initial_inputs)} {
|
||||||
|
}
|
||||||
|
|
||||||
|
void aoc2019::IntCodeComputer::sendInput(aoc2019::IntCodeComputer::value_t input) {
|
||||||
|
inputs.push_back(input);
|
||||||
|
}
|
||||||
|
|||||||
@@ -26,4 +26,32 @@ namespace aoc2019 {
|
|||||||
std::vector<int> read_intcode(std::istream &input);
|
std::vector<int> read_intcode(std::istream &input);
|
||||||
|
|
||||||
std::vector<int> run_intcode(std::vector<int> &program, std::deque<int> inputs = {});
|
std::vector<int> run_intcode(std::vector<int> &program, std::deque<int> inputs = {});
|
||||||
|
|
||||||
|
class IntCodeComputer {
|
||||||
|
public:
|
||||||
|
typedef std::int64_t value_t;
|
||||||
|
|
||||||
|
explicit IntCodeComputer(std::vector<value_t> program, std::deque<value_t> initial_inputs = {});
|
||||||
|
|
||||||
|
void run();
|
||||||
|
void connectOutput(IntCodeComputer &computer);
|
||||||
|
void connectOutput(std::deque<value_t> &sink);
|
||||||
|
void sendInput(value_t input);
|
||||||
|
|
||||||
|
[[nodiscard]] bool isTerminated() const;
|
||||||
|
|
||||||
|
[[nodiscard]] const std::deque<value_t> ¤tInputs() const;
|
||||||
|
|
||||||
|
static std::vector<value_t> read_intcode(std::istream &input);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<value_t> program;
|
||||||
|
std::deque<value_t> inputs = {};
|
||||||
|
std::deque<value_t> *outputSink = nullptr;
|
||||||
|
int ip = 0;
|
||||||
|
int relative = 0;
|
||||||
|
bool halted = false;
|
||||||
|
|
||||||
|
[[nodiscard]] value_t &interpret_value(int pos);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user