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 }