91 lines
2.1 KiB
C++
91 lines
2.1 KiB
C++
#include <array>
|
|
#include <cstddef>
|
|
#include <deque>
|
|
#include <iostream>
|
|
#include <stdexcept>
|
|
#include <utility>
|
|
#include <variant>
|
|
#include <vector>
|
|
|
|
#include <aocpp/Startup.hpp>
|
|
#include <intcode/intcode.hpp>
|
|
using namespace intcode;
|
|
|
|
namespace {
|
|
|
|
struct Payload { ValueType x, y; };
|
|
struct Packet { ValueType destination; Payload payload; };
|
|
using Ethernet = std::deque<Packet>;
|
|
using Machines = std::array<Machine, 50>;
|
|
|
|
auto BuildNetwork(Machine m) -> Machines {
|
|
Machines machines;
|
|
auto& i = std::get<Input>(Step(m)).input;
|
|
for (i = 0; i < std::int64_t(machines.size()); i++) {
|
|
machines[i] = m;
|
|
}
|
|
return machines;
|
|
}
|
|
|
|
auto Interact(Ethernet & ethernet, Machine & m, std::optional<Payload> p) -> void {
|
|
for(;;) {
|
|
auto e = Step(m);
|
|
switch (e.index()) {
|
|
default: throw std::runtime_error{"unexpected halt"};
|
|
case 0: {
|
|
auto& i = std::get<0>(e).input;
|
|
if (p) {
|
|
i = p->x;
|
|
StepInput(m, p->y);
|
|
p = {};
|
|
break;
|
|
}
|
|
i = -1; // no packet
|
|
return;
|
|
}
|
|
case 1: {
|
|
auto d = std::get<1>(e).output;
|
|
auto x = StepOutput(m);
|
|
auto y = StepOutput(m);
|
|
ethernet.push_back({d, {x,y}});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
|
|
auto Main(std::istream & in, std::ostream & out) -> void
|
|
{
|
|
auto machines = BuildNetwork(Machine{ParseStream(in)});
|
|
auto ethernet = Ethernet{};
|
|
|
|
std::optional<ValueType> part1;
|
|
std::optional<ValueType> part2;
|
|
std::optional<Payload> nat;
|
|
|
|
for(;;) {
|
|
if (!ethernet.empty()) {
|
|
auto const packet = ethernet.front();
|
|
ethernet.pop_front();
|
|
if (packet.destination == 255) {
|
|
nat = packet.payload;
|
|
if (!part1) { part1 = packet.payload.y; }
|
|
} else {
|
|
Interact(ethernet, machines.at(packet.destination), packet.payload);
|
|
}
|
|
} else if (nat) {
|
|
if (part2 == nat->y) { break; }
|
|
part2 = nat->y;
|
|
Interact(ethernet, machines[0], nat);
|
|
} else {
|
|
for (auto & m : machines) {
|
|
Interact(ethernet, m, {});
|
|
}
|
|
}
|
|
}
|
|
|
|
out << "Part 1: " << *part1 << std::endl;
|
|
out << "Part 2: " << *part2 << std::endl;
|
|
}
|