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 super::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 sent = Vec::new();
22    let mut nat_x = 0;
23    let mut nat_y = 0;
24    let mut first_y = None;
25    let mut idle_y = None;
26
27    loop {
28        let mut index = 0;
29        let mut empty = 0;
30
31        while index < 50 {
32            let computer = &mut network[index];
33
34            match computer.run() {
35                State::Output(value) => {
36                    // Loop until we have accumulated a full packet of 3 values.
37                    sent.push(value);
38                    let [address, x, y] = sent[..] else {
39                        continue;
40                    };
41                    sent.clear();
42
43                    if address == 255 {
44                        // Handle part one.
45                        first_y.get_or_insert(y);
46                        nat_x = x;
47                        nat_y = y;
48                    } else {
49                        let destination = &mut network[address as usize];
50                        destination.input(x);
51                        destination.input(y);
52                    }
53                }
54                // Input queue is empty.
55                State::Input => {
56                    empty += 1;
57                    computer.input(-1);
58                }
59                State::Halted => unreachable!(),
60            }
61
62            index += 1;
63        }
64
65        if empty == 50 {
66            if idle_y == Some(nat_y) {
67                break;
68            }
69            idle_y = Some(nat_y);
70
71            let destination = &mut network[0];
72            destination.input(nat_x);
73            destination.input(nat_y);
74        }
75    }
76
77    (first_y.unwrap(), idle_y.unwrap())
78}
79
80pub fn part1(input: &Input) -> i64 {
81    input.0
82}
83
84pub fn part2(input: &Input) -> i64 {
85    input.1
86}