1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
//! # Amplification Circuit
//!
//! Brute force solution for both parts using the utility [`permutations`] method to test each of
//! the possible 5! or 120 permutations of the phase settings.
//!
//! [`permutations`]: crate::util::slice
use super::intcode::*;
use crate::util::parse::*;
use crate::util::slice::*;
use std::array::from_fn;

pub fn parse(input: &str) -> Vec<i64> {
    input.iter_signed::<i64>().collect()
}

pub fn part1(input: &[i64]) -> i64 {
    let mut result = 0;
    let mut computer = Computer::new(input);

    let sequence = |slice: &[i64]| {
        let mut signal = 0;

        // Send exactly 2 inputs and receive exactly 1 output per amplifier.
        for &phase in slice {
            computer.reset();
            computer.input(phase);
            computer.input(signal);

            match computer.run() {
                State::Output(next) => signal = next,
                _ => unreachable!(),
            }
        }

        result = result.max(signal);
    };

    [0, 1, 2, 3, 4].permutations(sequence);
    result
}

pub fn part2(input: &[i64]) -> i64 {
    let mut result = 0;
    let mut computers: [Computer; 5] = from_fn(|_| Computer::new(input));

    let feedback = |slice: &[i64]| {
        // Reset state.
        computers.iter_mut().for_each(Computer::reset);

        // Send each initial phase setting exactly once.
        for (computer, &phase) in computers.iter_mut().zip(slice.iter()) {
            computer.input(phase);
        }

        // Chain amplifier inputs and ouputs in a loop until all threads finish.
        let mut signal = 0;

        'outer: loop {
            for computer in &mut computers {
                computer.input(signal);

                match computer.run() {
                    State::Output(next) => signal = next,
                    _ => break 'outer,
                }
            }
        }

        result = result.max(signal);
    };

    [5, 6, 7, 8, 9].permutations(feedback);
    result
}