#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 < 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(int const argc, char** const argv) -> int { auto machines = BuildNetwork(Machine{ParseStream(aocpp::Startup(argc, argv))}); 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, {}); } } } std::cout << "Part 1: " << *part1 << std::endl; std::cout << "Part 2: " << *part2 << std::endl; }