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 }