day-07.rs (8020B)
1 use std::collections::VecDeque;
2
3 fn main() {
4 let input = std::fs::read_to_string("input.txt")
5 .unwrap()
6 .trim()
7 .split(",")
8 .map(|op| op.parse::<i32>().unwrap())
9 .collect::<Vec<i32>>();
10 println!("Rust:");
11 println!("Part 1: {}", part_1(&input));
12 println!("Part 2: {}", part_2(&input));
13 }
14
15 fn computer(program: &Vec<i32>, input: &Vec<i32>) -> Vec<i32> {
16 let mut program = program.clone();
17 let mut input = input.clone().into_iter().collect::<VecDeque<i32>>();
18 let mut output = vec![];
19 let mut pc = 0;
20
21 loop {
22 let (finished, mut step_output) = computer_step(&mut program, &mut pc, input.pop_front());
23 output.append(&mut step_output);
24 if finished {
25 break;
26 }
27 }
28
29 output
30 }
31
32 fn computer_step(
33 program: &mut Vec<i32>,
34 pc: &mut usize,
35 mut input: Option<i32>,
36 ) -> (bool, Vec<i32>) {
37 // Runs from given pc until completion or next request for input.
38 // Modifies program and pc.
39 // Returns if the program has terminated and the output.
40 let mut output = vec![];
41
42 let get_param = |loc: usize, im_mode: bool, program: &Vec<i32>| -> i32 {
43 if im_mode {
44 program[loc]
45 } else {
46 program[program[loc] as usize]
47 }
48 };
49
50 loop {
51 let op_code = program[*pc] % 100;
52 let im_mode_1 = (program[*pc] % 1000) / 100 > 0;
53 let im_mode_2 = (program[*pc] % 10000) / 1000 > 0;
54 // Third parameter is location to write to, and will never be immediate
55 // mode.
56 match op_code {
57 1 => {
58 let res_loc = program[*pc + 3];
59 let param_1 = get_param(*pc + 1, im_mode_1, &program);
60 let param_2 = get_param(*pc + 2, im_mode_2, &program);
61 program[res_loc as usize] = param_1 + param_2;
62 *pc += 4;
63 }
64 2 => {
65 let res_loc = program[*pc + 3];
66 let param_1 = get_param(*pc + 1, im_mode_1, &program);
67 let param_2 = get_param(*pc + 2, im_mode_2, &program);
68 program[res_loc as usize] = param_1 * param_2;
69 *pc += 4;
70 }
71 3 => {
72 let res_loc = program[*pc + 1];
73 // Only use input once.
74 if input.is_some() {
75 program[res_loc as usize] = input.unwrap();
76 input = None;
77 } else {
78 // Need new input.
79 return (false, output);
80 };
81 *pc += 2;
82 }
83 4 => {
84 let param_1 = get_param(*pc + 1, im_mode_1, &program);
85 output.push(param_1);
86 *pc += 2;
87 }
88 5 => {
89 let param_1 = get_param(*pc + 1, im_mode_1, &program);
90 let param_2 = get_param(*pc + 2, im_mode_2, &program);
91 if param_1 != 0 {
92 *pc = param_2 as usize;
93 } else {
94 *pc += 3;
95 }
96 }
97 6 => {
98 let param_1 = get_param(*pc + 1, im_mode_1, &program);
99 let param_2 = get_param(*pc + 2, im_mode_2, &program);
100 if param_1 == 0 {
101 *pc = param_2 as usize;
102 } else {
103 *pc += 3;
104 }
105 }
106 7 => {
107 let res_loc = program[*pc + 3];
108 let param_1 = get_param(*pc + 1, im_mode_1, &program);
109 let param_2 = get_param(*pc + 2, im_mode_2, &program);
110 program[res_loc as usize] = if param_1 < param_2 { 1 } else { 0 };
111 *pc += 4;
112 }
113 8 => {
114 let res_loc = program[*pc + 3];
115 let param_1 = get_param(*pc + 1, im_mode_1, &program);
116 let param_2 = get_param(*pc + 2, im_mode_2, &program);
117 program[res_loc as usize] = if param_1 == param_2 { 1 } else { 0 };
118 *pc += 4;
119 }
120 99 => {
121 break;
122 }
123 _ => {
124 println!("Unknown op {}", op_code);
125 println!("{}", program[*pc]);
126 panic!();
127 }
128 }
129 }
130
131 (true, output)
132 }
133
134 fn feedback_amp(program: &Vec<i32>, phase: &Vec<i32>) -> i32 {
135 let num_amps = phase.len();
136 let mut programs = vec![program.clone(); num_amps];
137 let mut pcs = vec![0; num_amps];
138 let mut inputs = phase
139 .iter()
140 .map(|&x| {
141 let mut input = VecDeque::<i32>::new();
142 input.push_back(x);
143 input
144 })
145 .collect::<Vec<VecDeque<i32>>>();
146
147 // Additional input for first amplifier.
148 inputs[0].push_back(0);
149 // Index of currently working amp.
150 let mut work_idx = 0;
151 loop {
152 // Run current amp.
153 let (finished, step_output) = computer_step(
154 &mut programs[work_idx],
155 &mut pcs[work_idx],
156 inputs[work_idx].pop_front(),
157 );
158 // Pipe output to next amp.
159 step_output
160 .into_iter()
161 .for_each(|x| inputs[(work_idx + 1) % num_amps].push_back(x));
162 // Check for completion.
163 if finished && work_idx + 1 == num_amps {
164 break;
165 }
166 // Move to next amp.
167 work_idx = (work_idx + 1) % num_amps;
168 }
169
170 *inputs[0].back().unwrap()
171 }
172
173 fn part_1(input: &Vec<i32>) -> i32 {
174 let mut max_output = 0;
175 for phase_1 in 0..=4 {
176 let out_1 = computer(input, &vec![phase_1, 0])[0];
177 for phase_2 in 0..=4 {
178 if phase_2 == phase_1 {
179 continue;
180 }
181 let out_2 = computer(input, &vec![phase_2, out_1])[0];
182 for phase_3 in 0..=4 {
183 if phase_3 == phase_1 || phase_3 == phase_2 {
184 continue;
185 }
186 let out_3 = computer(input, &vec![phase_3, out_2])[0];
187 for phase_4 in 0..=4 {
188 if phase_4 == phase_1 || phase_4 == phase_2 || phase_4 == phase_3 {
189 continue;
190 }
191 let out_4 = computer(input, &vec![phase_4, out_3])[0];
192 for phase_5 in 0..=4 {
193 if phase_5 == phase_1
194 || phase_5 == phase_2
195 || phase_5 == phase_3
196 || phase_5 == phase_4
197 {
198 continue;
199 }
200 let out_5 = computer(input, &vec![phase_5, out_4])[0];
201 max_output = max_output.max(out_5);
202 }
203 }
204 }
205 }
206 }
207
208 max_output
209 }
210
211 fn part_2(input: &Vec<i32>) -> i32 {
212 let mut max_output = 0;
213
214 for phase_1 in 5..=9 {
215 for phase_2 in 5..=9 {
216 if phase_2 == phase_1 {
217 continue;
218 }
219 for phase_3 in 5..=9 {
220 if phase_3 == phase_1 || phase_3 == phase_2 {
221 continue;
222 }
223 for phase_4 in 5..=9 {
224 if phase_4 == phase_1 || phase_4 == phase_2 || phase_4 == phase_3 {
225 continue;
226 }
227 for phase_5 in 5..=9 {
228 if phase_5 == phase_1
229 || phase_5 == phase_2
230 || phase_5 == phase_3
231 || phase_5 == phase_4
232 {
233 continue;
234 }
235 max_output = max_output.max(feedback_amp(
236 input,
237 &vec![phase_1, phase_2, phase_3, phase_4, phase_5],
238 ));
239 }
240 }
241 }
242 }
243 }
244
245 max_output
246 }