day-13.rs (8372B)
1 use std::collections::HashMap; 2 use std::io::prelude::*; 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: "); 15 part_2(&input); 16 } 17 18 fn computer_step( 19 program: &mut HashMap<usize, Op>, 20 pc: &mut usize, 21 relative_base: &mut Op, 22 input: &mut Option<Op>, 23 ) -> (bool, Vec<Op>) { 24 let mut output = vec![]; 25 let get_param = |loc: usize, mode, program: &HashMap<usize, Op>, relative_base: &Op| -> Op { 26 match mode { 27 // Position mode. 28 0 => *program.get(&(program[&loc] as usize)).unwrap_or(&0), 29 // Immediate mode. 30 1 => program[&loc], 31 // Relative mode. 32 2 => *program 33 .get(&((*relative_base + program[&loc]) as usize)) 34 .unwrap_or(&0), 35 _ => panic!(), 36 } 37 }; 38 39 let get_res_loc = 40 |loc: usize, mode, program: &HashMap<usize, Op>, relative_base: &Op| -> usize { 41 match mode { 42 // Position mode. 43 0 => program[&loc] as usize, 44 // Immediate mode is banned. 45 // Relative mode. 46 2 => (relative_base + program[&loc]) as usize, 47 _ => panic!(), 48 } 49 }; 50 51 loop { 52 let op_code = program[pc] % 100; 53 let mode_1 = (program[pc] % 1000) / 100; 54 let mode_2 = (program[pc] % 10000) / 1000; 55 let mode_3 = (program[pc] % 100000) / 10000; 56 match op_code { 57 1 => { 58 let res_loc = get_res_loc(*pc + 3, mode_3, &program, relative_base); 59 let param_1 = get_param(*pc + 1, mode_1, &program, relative_base); 60 let param_2 = get_param(*pc + 2, mode_2, &program, relative_base); 61 *program.entry(res_loc).or_default() = param_1 + param_2; 62 *pc += 4; 63 } 64 2 => { 65 let res_loc = get_res_loc(*pc + 3, mode_3, &program, relative_base); 66 let param_1 = get_param(*pc + 1, mode_1, &program, relative_base); 67 let param_2 = get_param(*pc + 2, mode_2, &program, relative_base); 68 *program.entry(res_loc as usize).or_default() = param_1 * param_2; 69 *pc += 4; 70 } 71 3 => { 72 let res_loc = get_res_loc(*pc + 1, mode_1, &program, relative_base); 73 // Only use input once. 74 if input.is_some() { 75 *program.entry(res_loc as usize).or_default() = 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, mode_1, &program, relative_base); 85 output.push(param_1); 86 *pc += 2; 87 } 88 5 => { 89 let param_1 = get_param(*pc + 1, mode_1, &program, relative_base); 90 let param_2 = get_param(*pc + 2, mode_2, &program, relative_base); 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, mode_1, &program, relative_base); 99 let param_2 = get_param(*pc + 2, mode_2, &program, relative_base); 100 if param_1 == 0 { 101 *pc = param_2 as usize; 102 } else { 103 *pc += 3; 104 } 105 } 106 7 => { 107 let res_loc = get_res_loc(*pc + 3, mode_3, &program, relative_base); 108 let param_1 = get_param(*pc + 1, mode_1, &program, relative_base); 109 let param_2 = get_param(*pc + 2, mode_2, &program, relative_base); 110 *program.entry(res_loc as usize).or_default() = 111 if param_1 < param_2 { 1 } else { 0 }; 112 *pc += 4; 113 } 114 8 => { 115 let res_loc = get_res_loc(*pc + 3, mode_3, &program, relative_base); 116 let param_1 = get_param(*pc + 1, mode_1, &program, relative_base); 117 let param_2 = get_param(*pc + 2, mode_2, &program, relative_base); 118 *program.entry(res_loc as usize).or_default() = 119 if param_1 == param_2 { 1 } else { 0 }; 120 *pc += 4; 121 } 122 9 => { 123 let param_1 = get_param(*pc + 1, mode_1, &program, relative_base); 124 *relative_base += param_1; 125 *pc += 2; 126 } 127 99 => { 128 break; 129 } 130 _ => { 131 println!("Unknown op {}", op_code); 132 println!("{}", program[pc]); 133 panic!(); 134 } 135 } 136 } 137 138 (true, output) 139 } 140 141 fn arcade(program: &Vec<Op>, demo: bool, cheat: bool) -> HashMap<(Op, Op), usize> { 142 let mut program = program 143 .iter() 144 .enumerate() 145 .map(|(idx, &op)| (idx, op)) 146 .collect::<HashMap<usize, Op>>(); 147 if !demo { 148 *program.entry(0).or_default() = 2; 149 if cheat { 150 // Replace bottom opening with walls. 151 (1583..1622).for_each(|i| { 152 *program.get_mut(&i).unwrap() = 1; 153 }); 154 } 155 } 156 // Set program state. 157 let mut pc = 0; 158 let mut relative_base = 0; 159 let mut screen = HashMap::<(Op, Op), usize>::new(); 160 let mut command = None; 161 // Prepare for user input. 162 let stdin = std::io::stdin(); 163 let mut user_input = [0; 1]; 164 // Main loop. 165 loop { 166 let (finished, step_output) = 167 computer_step(&mut program, &mut pc, &mut relative_base, &mut command); 168 // Parse step_output. 169 step_output 170 .chunks_exact(3) 171 .to_owned() 172 .for_each(|cmd| *screen.entry((cmd[0], cmd[1])).or_default() = cmd[2] as usize); 173 if !demo { 174 if cheat { 175 command = Some(-1); 176 // Break when there's no block left. 177 if count_blocks(&screen) == 0 { 178 break; 179 } 180 } else { 181 draw(&screen); 182 // Read next input. 183 println!("Move left with <h>, and move right with <l>:"); 184 while command.is_none() { 185 let mut handle = stdin.lock(); 186 handle.read(&mut user_input[..]).ok(); 187 match user_input[0] as char { 188 'h' => command = Some(-1), 189 'l' => command = Some(1), 190 _ => command = Some(0), 191 } 192 } 193 } 194 } 195 if finished { 196 break; 197 } 198 } 199 screen 200 } 201 202 fn count_blocks(screen: &HashMap<(Op, Op), usize>) -> usize { 203 screen.values().filter(|x| **x == 2).count() 204 } 205 206 fn draw(screen: &HashMap<(Op, Op), usize>) { 207 // Check max coordinates. 208 let mut max_x = Op::min_value(); 209 let mut max_y = Op::min_value(); 210 // Find score. 211 let mut score = 0; 212 for panel in screen.keys() { 213 max_x = max_x.max(panel.0); 214 max_y = max_y.max(panel.1); 215 if *panel == (-1, 0) { 216 score = screen[panel]; 217 } 218 } 219 // Print the panels. 220 for y in 0..=max_y { 221 for x in 0..=max_x { 222 match *screen.get(&(x, y)).unwrap_or(&0) { 223 // Wall 224 1 => print!("||"), 225 // Block 226 2 => print!("##"), 227 // Paddle 228 3 => print!("--"), 229 // Ball 230 4 => print!("[]"), 231 // Empty 232 _ => print!(" "), 233 } 234 } 235 println!(); 236 } 237 // Print score. 238 println!("score: {}", score); 239 } 240 241 fn part_1(input: &Vec<Op>) -> usize { 242 let screen = arcade(input, true, false); 243 count_blocks(&screen) 244 } 245 246 fn part_2(input: &Vec<Op>) { 247 // Enable cheat and draw last screen for scores. 248 let screen = arcade(input, false, true); 249 draw(&screen); 250 }