day-17.rs (8577B)
1 use std::collections::HashMap; 2 use std::collections::VecDeque; 3 type Op = i128; 4 5 fn main() { 6 let input = std::fs::read_to_string("input.txt") 7 .unwrap() 8 .trim() 9 .split(",") 10 .map(|op| op.parse::<Op>().unwrap()) 11 .collect::<Vec<Op>>(); 12 println!("Rust:"); 13 println!("Part 1: {}", part_1(&input)); 14 println!("Part 2: {}", part_2(&input)); 15 } 16 17 fn computer_step( 18 program: &mut HashMap<usize, Op>, 19 pc: &mut usize, 20 relative_base: &mut Op, 21 input: &mut Option<Op>, 22 ) -> (bool, Vec<Op>) { 23 let mut output = vec![]; 24 let get_param = |loc: usize, mode, program: &HashMap<usize, Op>, relative_base: &Op| -> Op { 25 match mode { 26 // Position mode. 27 0 => *program.get(&(program[&loc] as usize)).unwrap_or(&0), 28 // Immediate mode. 29 1 => program[&loc], 30 // Relative mode. 31 2 => *program 32 .get(&((*relative_base + program[&loc]) as usize)) 33 .unwrap_or(&0), 34 _ => panic!(), 35 } 36 }; 37 38 let get_res_loc = 39 |loc: usize, mode, program: &HashMap<usize, Op>, relative_base: &Op| -> usize { 40 match mode { 41 // Position mode. 42 0 => program[&loc] as usize, 43 // Immediate mode is banned. 44 // Relative mode. 45 2 => (relative_base + program[&loc]) as usize, 46 _ => panic!(), 47 } 48 }; 49 50 loop { 51 let op_code = program[pc] % 100; 52 let mode_1 = (program[pc] % 1000) / 100; 53 let mode_2 = (program[pc] % 10000) / 1000; 54 let mode_3 = (program[pc] % 100000) / 10000; 55 match op_code { 56 1 => { 57 let res_loc = get_res_loc(*pc + 3, mode_3, &program, relative_base); 58 let param_1 = get_param(*pc + 1, mode_1, &program, relative_base); 59 let param_2 = get_param(*pc + 2, mode_2, &program, relative_base); 60 *program.entry(res_loc).or_default() = param_1 + param_2; 61 *pc += 4; 62 } 63 2 => { 64 let res_loc = get_res_loc(*pc + 3, mode_3, &program, relative_base); 65 let param_1 = get_param(*pc + 1, mode_1, &program, relative_base); 66 let param_2 = get_param(*pc + 2, mode_2, &program, relative_base); 67 *program.entry(res_loc as usize).or_default() = param_1 * param_2; 68 *pc += 4; 69 } 70 3 => { 71 let res_loc = get_res_loc(*pc + 1, mode_1, &program, relative_base); 72 // Only use input once. 73 if input.is_some() { 74 *program.entry(res_loc as usize).or_default() = input.unwrap(); 75 *input = None; 76 } else { 77 // Need new input. 78 return (false, output); 79 }; 80 *pc += 2; 81 } 82 4 => { 83 let param_1 = get_param(*pc + 1, mode_1, &program, relative_base); 84 output.push(param_1); 85 *pc += 2; 86 } 87 5 => { 88 let param_1 = get_param(*pc + 1, mode_1, &program, relative_base); 89 let param_2 = get_param(*pc + 2, mode_2, &program, relative_base); 90 if param_1 != 0 { 91 *pc = param_2 as usize; 92 } else { 93 *pc += 3; 94 } 95 } 96 6 => { 97 let param_1 = get_param(*pc + 1, mode_1, &program, relative_base); 98 let param_2 = get_param(*pc + 2, mode_2, &program, relative_base); 99 if param_1 == 0 { 100 *pc = param_2 as usize; 101 } else { 102 *pc += 3; 103 } 104 } 105 7 => { 106 let res_loc = get_res_loc(*pc + 3, mode_3, &program, relative_base); 107 let param_1 = get_param(*pc + 1, mode_1, &program, relative_base); 108 let param_2 = get_param(*pc + 2, mode_2, &program, relative_base); 109 *program.entry(res_loc as usize).or_default() = 110 if param_1 < param_2 { 1 } else { 0 }; 111 *pc += 4; 112 } 113 8 => { 114 let res_loc = get_res_loc(*pc + 3, mode_3, &program, relative_base); 115 let param_1 = get_param(*pc + 1, mode_1, &program, relative_base); 116 let param_2 = get_param(*pc + 2, mode_2, &program, relative_base); 117 *program.entry(res_loc as usize).or_default() = 118 if param_1 == param_2 { 1 } else { 0 }; 119 *pc += 4; 120 } 121 9 => { 122 let param_1 = get_param(*pc + 1, mode_1, &program, relative_base); 123 *relative_base += param_1; 124 *pc += 2; 125 } 126 99 => { 127 break; 128 } 129 _ => { 130 println!("Unknown op {}", op_code); 131 println!("{}", program[pc]); 132 panic!(); 133 } 134 } 135 } 136 (true, output) 137 } 138 139 fn get_view(input: &Vec<Op>) -> Vec<Vec<char>> { 140 // Get view of the scaffoldings. 141 let mut program = input 142 .iter() 143 .enumerate() 144 .map(|(idx, &op)| (idx, op)) 145 .collect::<HashMap<usize, Op>>(); 146 // Set program state. 147 let mut pc = 0; 148 let mut relative_base = 0; 149 let (_, output) = computer_step(&mut program, &mut pc, &mut relative_base, &mut None); 150 // Split output into vector of vector. 151 let width = output 152 .iter() 153 .enumerate() 154 .filter(|(_, &op)| op == 10) 155 .next() 156 .unwrap() 157 .0 158 + 1; 159 // No need to include the new lines at the end. 160 output[..(output.len() - 1)] 161 .chunks(width) 162 .map(|chunk| { 163 chunk 164 .iter() 165 .filter(|&&op| op != 10) 166 .map(|&op| op as u8 as char) 167 .collect() 168 }) 169 .collect() 170 } 171 172 fn print_view(view: &Vec<Vec<char>>) { 173 for row in view { 174 for px in row { 175 print!("{}", px); 176 } 177 println!(); 178 } 179 } 180 181 fn calc_alignment_parameter(view: &Vec<Vec<char>>) -> usize { 182 // Get view width. 183 let width = view[0].len(); 184 let height = view.len(); 185 let mut alignment_param = 0; 186 // Current coordinate. 187 // No intersection can occur on the borders. 188 for x in 1..(width - 1) { 189 for y in 1..(height - 1) { 190 // Check for intersection. 191 // All 5 squares should be scaffolding. 192 if view[y][x] != '.' 193 && view[y][x + 1] != '.' 194 && view[y][x - 1] != '.' 195 && view[y + 1][x] != '.' 196 && view[y - 1][x] != '.' 197 { 198 alignment_param += x * y; 199 } 200 } 201 } 202 alignment_param 203 } 204 205 fn collect_dust( 206 input: &Vec<Op>, 207 main_routine: &Vec<Op>, 208 func_a: &Vec<Op>, 209 func_b: &Vec<Op>, 210 func_c: &Vec<Op>, 211 ) -> usize { 212 let mut program = input 213 .iter() 214 .enumerate() 215 .map(|(idx, &op)| (idx, op)) 216 .collect::<HashMap<usize, Op>>(); 217 // Enable movements. 218 *program.get_mut(&0).unwrap() = 2; 219 // Set program state. 220 let mut pc = 0; 221 let mut relative_base = 0; 222 // Assemble commands. 223 let mut commands = main_routine 224 .iter() 225 .chain(func_a) 226 .chain(func_b) 227 .chain(func_c) 228 .chain(&['n' as u8 as Op, '\n' as u8 as Op]) // No video feeds. 229 .cloned() 230 .collect::<VecDeque<Op>>(); 231 // Collect output. 232 let mut output = Vec::new(); 233 // Run program. 234 loop { 235 let (finished, mut step_output) = computer_step( 236 &mut program, 237 &mut pc, 238 &mut relative_base, 239 &mut commands.pop_front(), 240 ); 241 output.append(&mut step_output); 242 if finished { 243 break; 244 } 245 } 246 *output.last().unwrap() as usize 247 } 248 249 fn part_1(input: &Vec<Op>) -> usize { 250 let view = get_view(input); 251 print_view(&view); 252 calc_alignment_parameter(&view) 253 } 254 255 fn part_2(input: &Vec<Op>) -> usize { 256 let cmd_to_ascii = |cmd: &str| -> Vec<Op> { cmd.chars().map(|ch| ch as u8 as Op).collect() }; 257 let main_routine = cmd_to_ascii("A,B,A,B,C,A,B,C,A,C\n"); 258 let func_a = cmd_to_ascii("R,6,L,6,L,10\n"); 259 let func_b = cmd_to_ascii("L,8,L,6,L,10,L,6\n"); 260 let func_c = cmd_to_ascii("R,6,L,8,L,10,R,6\n"); 261 collect_dust(input, &main_routine, &func_a, &func_b, &func_c) 262 }