#include #include #include #include #include #include #include #include #include #include using namespace intcode; namespace { struct Payload { ValueType x, y; }; struct Packet { ValueType destination; Payload payload; }; using Ethernet = std::deque; using Machines = std::array; auto BuildNetwork(Machine m) -> Machines { Machines machines; auto& i = std::get(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 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 part1; std::optional part2; std::optional 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; }