day-11.rs (7731B)
1 use std::collections::HashMap; 2 type Op = i128; 3 4 fn main() { 5 let input = std::fs::read_to_string("input.txt") 6 .unwrap() 7 .trim() 8 .split(",") 9 .map(|op| op.parse::<Op>().unwrap()) 10 .collect::<Vec<Op>>(); 11 println!("Rust:"); 12 println!("Part 1: {}", part_1(&input)); 13 println!("Part 2: "); 14 part_2(&input); 15 } 16 17 fn turn_left(dir: (Op, Op)) -> (Op, Op) { 18 // Takes in dir in the form of (0, 1). 19 match dir { 20 (0, 1) => (-1, 0), 21 (1, 0) => (0, 1), 22 (0, -1) => (1, 0), 23 (-1, 0) => (0, -1), 24 _ => panic!(), 25 } 26 } 27 28 fn turn_right(dir: (Op, Op)) -> (Op, Op) { 29 // Takes in dir in the form of (0, 1). 30 match dir { 31 (0, 1) => (1, 0), 32 (1, 0) => (0, -1), 33 (0, -1) => (-1, 0), 34 (-1, 0) => (0, 1), 35 _ => panic!(), 36 } 37 } 38 39 fn robot(program: &Vec<Op>, panels: &mut HashMap<(Op, Op), usize>) { 40 let mut program = program 41 .iter() 42 .enumerate() 43 .map(|(idx, &op)| (idx, op)) 44 .collect::<HashMap<usize, Op>>(); 45 let mut pc = 0; 46 let mut relative_base = 0; 47 let mut coord = (0, 0); 48 // Initially facing north. 49 let mut dir = (0, 1); 50 51 loop { 52 // Get color for current panel. Panels start black (0). 53 // This records only panels the robot has stepped on. 54 let color = panels.entry(coord).or_insert(0); 55 let (finished, step_output) = computer_step( 56 &mut program, 57 &mut pc, 58 &mut relative_base, 59 Some(*color as Op), 60 ); 61 // First instruction is color to paint the panel to. 62 *panels.get_mut(&coord).unwrap() = step_output[0] as usize; 63 // Second instruction is direction to turn the robot. 64 if step_output[1] == 0 { 65 dir = turn_left(dir); 66 } else { 67 dir = turn_right(dir); 68 } 69 // Move robot forward by one panel. 70 coord = (coord.0 + dir.0, coord.1 + dir.1); 71 if finished { 72 break; 73 } 74 } 75 } 76 77 fn computer_step( 78 program: &mut HashMap<usize, Op>, 79 pc: &mut usize, 80 relative_base: &mut Op, 81 mut input: Option<Op>, 82 ) -> (bool, Vec<Op>) { 83 let mut output = vec![]; 84 let get_param = |loc: usize, mode, program: &HashMap<usize, Op>, relative_base: &Op| -> Op { 85 match mode { 86 // Position mode. 87 0 => *program.get(&(program[&loc] as usize)).unwrap_or(&0), 88 // Immediate mode. 89 1 => program[&loc], 90 // Relative mode. 91 2 => *program 92 .get(&((*relative_base + program[&loc]) as usize)) 93 .unwrap_or(&0), 94 _ => panic!(), 95 } 96 }; 97 98 let get_res_loc = 99 |loc: usize, mode, program: &HashMap<usize, Op>, relative_base: &Op| -> usize { 100 match mode { 101 // Position mode. 102 0 => program[&loc] as usize, 103 // Immediate mode is banned. 104 // Relative mode. 105 2 => (relative_base + program[&loc]) as usize, 106 _ => panic!(), 107 } 108 }; 109 110 loop { 111 let op_code = program[pc] % 100; 112 let mode_1 = (program[pc] % 1000) / 100; 113 let mode_2 = (program[pc] % 10000) / 1000; 114 let mode_3 = (program[pc] % 100000) / 10000; 115 match op_code { 116 1 => { 117 let res_loc = get_res_loc(*pc + 3, mode_3, &program, relative_base); 118 let param_1 = get_param(*pc + 1, mode_1, &program, relative_base); 119 let param_2 = get_param(*pc + 2, mode_2, &program, relative_base); 120 *program.entry(res_loc).or_default() = param_1 + param_2; 121 *pc += 4; 122 } 123 2 => { 124 let res_loc = get_res_loc(*pc + 3, mode_3, &program, relative_base); 125 let param_1 = get_param(*pc + 1, mode_1, &program, relative_base); 126 let param_2 = get_param(*pc + 2, mode_2, &program, relative_base); 127 *program.entry(res_loc as usize).or_default() = param_1 * param_2; 128 *pc += 4; 129 } 130 3 => { 131 let res_loc = get_res_loc(*pc + 1, mode_1, &program, relative_base); 132 // Only use input once. 133 if input.is_some() { 134 *program.entry(res_loc as usize).or_default() = input.unwrap(); 135 input = None; 136 } else { 137 // Need new input. 138 return (false, output); 139 }; 140 *pc += 2; 141 } 142 4 => { 143 let param_1 = get_param(*pc + 1, mode_1, &program, relative_base); 144 output.push(param_1); 145 *pc += 2; 146 } 147 5 => { 148 let param_1 = get_param(*pc + 1, mode_1, &program, relative_base); 149 let param_2 = get_param(*pc + 2, mode_2, &program, relative_base); 150 if param_1 != 0 { 151 *pc = param_2 as usize; 152 } else { 153 *pc += 3; 154 } 155 } 156 6 => { 157 let param_1 = get_param(*pc + 1, mode_1, &program, relative_base); 158 let param_2 = get_param(*pc + 2, mode_2, &program, relative_base); 159 if param_1 == 0 { 160 *pc = param_2 as usize; 161 } else { 162 *pc += 3; 163 } 164 } 165 7 => { 166 let res_loc = get_res_loc(*pc + 3, mode_3, &program, relative_base); 167 let param_1 = get_param(*pc + 1, mode_1, &program, relative_base); 168 let param_2 = get_param(*pc + 2, mode_2, &program, relative_base); 169 *program.entry(res_loc as usize).or_default() = 170 if param_1 < param_2 { 1 } else { 0 }; 171 *pc += 4; 172 } 173 8 => { 174 let res_loc = get_res_loc(*pc + 3, mode_3, &program, relative_base); 175 let param_1 = get_param(*pc + 1, mode_1, &program, relative_base); 176 let param_2 = get_param(*pc + 2, mode_2, &program, relative_base); 177 *program.entry(res_loc as usize).or_default() = 178 if param_1 == param_2 { 1 } else { 0 }; 179 *pc += 4; 180 } 181 9 => { 182 let param_1 = get_param(*pc + 1, mode_1, &program, relative_base); 183 *relative_base += param_1; 184 *pc += 2; 185 } 186 99 => { 187 break; 188 } 189 _ => { 190 println!("Unknown op {}", op_code); 191 println!("{}", program[pc]); 192 panic!(); 193 } 194 } 195 } 196 197 (true, output) 198 } 199 200 fn part_1(input: &Vec<Op>) -> usize { 201 let mut panels = HashMap::new(); 202 robot(input, &mut panels); 203 panels.len() 204 } 205 206 fn part_2(input: &Vec<Op>) { 207 let mut panels = HashMap::new(); 208 // Set initial panel white. 209 panels.insert((0, 0), 1); 210 robot(input, &mut panels); 211 // Display the panel results. 212 // Check max/min coordinates. 213 let mut min_x = Op::max_value(); 214 let mut max_x = Op::min_value(); 215 let mut min_y = Op::max_value(); 216 let mut max_y = Op::min_value(); 217 for panel in panels.keys() { 218 min_x = min_x.min(panel.0); 219 max_x = max_x.max(panel.0); 220 min_y = min_y.min(panel.1); 221 max_y = max_y.max(panel.1); 222 } 223 // Print the panels. 224 for y in (min_y..=max_y).rev() { 225 for x in min_x..=max_x { 226 match *panels.get(&(x, y)).unwrap_or(&0) { 227 1 => print!("██"), 228 _ => print!(" "), 229 } 230 } 231 println!(); 232 } 233 }