Skip to main content

aoc/year2019/
day23.rs

1//! # Category Six
2//!
3//! Solves both part one and two simultaneously. A nice benefit of our intcode computer is that it
4//! returns [`State::Input`] when the input queue is empty, making it easy to detect an
5//! idle network.
6use crate::util::intcode::*;
7use crate::util::parse::*;
8
9type Input = (i64, i64);
10
11pub fn parse(input: &str) -> Input {
12    let code: Vec<_> = input.iter_signed().collect();
13    let mut network: Vec<_> = (0..50)
14        .map(|address| {
15            let mut computer = Computer::new(&code);
16            computer.input(address);
17            computer
18        })
19        .collect();
20
21    let mut nat_x = 0;
22    let mut nat_y = 0;
23    let mut first_y = None;
24    let mut idle_y = None;
25
26    loop {
27        let mut empty = 0;
28
29        for index in 0..50 {
30            let computer = &mut network[index];
31
32            match computer.run() {
33                State::Output(address) => {
34                    // Each packet contains a destination address followed by x and y.
35                    let State::Output(x) = computer.run() else { unreachable!() };
36                    let State::Output(y) = computer.run() else { unreachable!() };
37
38                    if address == 255 {
39                        // Handle part one.
40                        first_y.get_or_insert(y);
41                        nat_x = x;
42                        nat_y = y;
43                    } else {
44                        let destination = &mut network[address as usize];
45                        destination.input(x);
46                        destination.input(y);
47                    }
48                }
49                // Input queue is empty.
50                State::Input => {
51                    empty += 1;
52                    computer.input(-1);
53                }
54                State::Halted => unreachable!(),
55            }
56        }
57
58        if empty == 50 {
59            if idle_y == Some(nat_y) {
60                break;
61            }
62            idle_y = Some(nat_y);
63
64            let destination = &mut network[0];
65            destination.input(nat_x);
66            destination.input(nat_y);
67        }
68    }
69
70    (first_y.unwrap(), idle_y.unwrap())
71}
72
73pub fn part1(input: &Input) -> i64 {
74    input.0
75}
76
77pub fn part2(input: &Input) -> i64 {
78    input.1
79}