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 }