Skip to main content

advent_of_code/year2019/
day17.rs

1use super::int_code::Program;
2use crate::input::Input;
3use std::collections::VecDeque;
4use std::slice::Iter;
5
6fn part1_map(map: &str) -> Result<String, String> {
7    let map: Vec<&[u8]> = map.trim().lines().map(str::as_bytes).collect();
8    if map.len() < 3 {
9        return Err("Too small input (less than three lines)".to_string());
10    } else if map.iter().filter(|row| row.len() != map[0].len()).count() > 0 {
11        return Err("Invalid map - not all rows are of equal length".to_string());
12    }
13
14    let mut alignment_parameters_sum = 0;
15    for y in 1..(map.len() - 1) {
16        for x in 1..(map[0].len() - 1) {
17            if map[y][x] == b'#'
18                && map[y][x - 1] == b'#'
19                && map[y][x + 1] == b'#'
20                && map[y - 1][x] == b'#'
21                && map[y + 1][x] == b'#'
22            {
23                alignment_parameters_sum += x * y;
24            }
25        }
26    }
27
28    Ok(alignment_parameters_sum.to_string())
29}
30
31#[derive(Debug, Clone, Copy, PartialEq)]
32enum Direction {
33    Up = 0,
34    Right,
35    Down,
36    Left,
37}
38
39impl Direction {
40    const fn turn_right(self) -> Self {
41        match self {
42            Self::Up => Self::Right,
43            Self::Right => Self::Down,
44            Self::Down => Self::Left,
45            Self::Left => Self::Up,
46        }
47    }
48
49    const fn turn_left(self) -> Self {
50        match self {
51            Self::Up => Self::Left,
52            Self::Right => Self::Up,
53            Self::Down => Self::Right,
54            Self::Left => Self::Down,
55        }
56    }
57
58    const fn other(self) -> Self {
59        match self {
60            Self::Up => Self::Down,
61            Self::Right => Self::Left,
62            Self::Down => Self::Up,
63            Self::Left => Self::Right,
64        }
65    }
66
67    const fn advance(self, position: (i32, i32)) -> (i32, i32) {
68        match self {
69            Self::Up => (position.0, position.1 - 1),
70            Self::Right => (position.0 + 1, position.1),
71            Self::Down => (position.0, position.1 + 1),
72            Self::Left => (position.0 - 1, position.1),
73        }
74    }
75
76    fn instruction_for_turning_to(self, target: Self) -> Result<char, String> {
77        if self.turn_right() == target {
78            Ok('R')
79        } else if self.turn_left() == target {
80            Ok('L')
81        } else {
82            Err(format!("Cannot turn from {self:?} to {target:?}"))
83        }
84    }
85
86    pub fn iterator() -> Iter<'static, Self> {
87        static DIRECTIONS: [Direction; 4] = [
88            Direction::Up,
89            Direction::Right,
90            Direction::Down,
91            Direction::Left,
92        ];
93        DIRECTIONS.iter()
94    }
95}
96
97// Solution taken from https://github.com/emlun/adventofcode-2019/blob/master/src/days/day17.rs
98pub fn solve(input: &Input) -> Result<String, String> {
99    let mut program = Program::parse(input.text)?;
100
101    if input.is_part_one() {
102        let output = program.run_for_output()?;
103        let map: String = output.iter().map(|&b| (b as u8) as char).collect();
104        return part1_map(&map);
105    }
106
107    program.write_memory(0, 2);
108
109    let output = program.run_for_output()?;
110    let map: String = output.iter().map(|&b| (b as u8) as char).collect();
111    let map: Vec<&[u8]> = map.lines().map(str::as_bytes).collect();
112    // Strip away last two lines with blank line and "Main:" prompt:
113    if map.len() < 5 {
114        return Err("Too small input (less than five lines)".to_string());
115    }
116    let map = &map[0..(map.len() - 2)];
117
118    if map.iter().filter(|row| row.len() != map[0].len()).count() > 0 {
119        return Err("Invalid map - not all rows are of equal length".to_string());
120    }
121
122    let mut robot_direction = Direction::Up;
123    let mut robot_position: (i32, i32) = (0, 0);
124    for (y, row) in map.iter().enumerate() {
125        for (x, &tile) in row.iter().enumerate() {
126            if tile == b'^' {
127                robot_direction = Direction::Up;
128                robot_position = (x as i32, y as i32);
129            } else if tile == b'v' {
130                robot_direction = Direction::Down;
131                robot_position = (x as i32, y as i32);
132            } else if tile == b'<' {
133                robot_direction = Direction::Left;
134                robot_position = (x as i32, y as i32);
135            } else if tile == b'>' {
136                robot_direction = Direction::Right;
137                robot_position = (x as i32, y as i32);
138            }
139        }
140    }
141
142    let mut starting = true;
143    let mut moves_since_turn = 0;
144    let mut movements = Vec::new();
145
146    loop {
147        let continuing_position = robot_direction.advance(robot_position);
148        if continuing_position.0 >= 0
149            && continuing_position.0 < map[0].len() as i32
150            && continuing_position.1 >= 0
151            && continuing_position.1 < map.len() as i32
152            && map[continuing_position.1 as usize][continuing_position.0 as usize] == b'#'
153        {
154            robot_position = continuing_position;
155            moves_since_turn += 1;
156            continue;
157        }
158
159        let mut possible_directions = Vec::new();
160        for &direction in Direction::iterator() {
161            let new_location = direction.advance(robot_position);
162            if new_location.0 >= 0
163                && new_location.0 < map[0].len() as i32
164                && new_location.1 >= 0
165                && new_location.1 < map.len() as i32
166                && map[new_location.1 as usize][new_location.0 as usize] == b'#'
167            {
168                possible_directions.push(direction);
169            }
170        }
171
172        if possible_directions.len() == 1 {
173            if starting {
174                if moves_since_turn != 0 {
175                    return Err("Starting with moves already performed".to_string());
176                }
177                starting = false;
178                movements.push(
179                    robot_direction
180                        .instruction_for_turning_to(possible_directions[0])?
181                        .to_string(),
182                );
183                robot_direction = possible_directions[0];
184                moves_since_turn = 0;
185            } else {
186                // Done.
187                if moves_since_turn > 0 {
188                    movements.push(moves_since_turn.to_string());
189                }
190                break;
191            }
192        } else if possible_directions.len() == 2 {
193            let new_direction = if possible_directions[0] == robot_direction.other() {
194                possible_directions[1]
195            } else {
196                possible_directions[0]
197            };
198
199            if new_direction == robot_direction {
200                robot_position = robot_direction.advance(robot_position);
201                moves_since_turn += 1;
202            } else {
203                if moves_since_turn > 0 {
204                    movements.push(moves_since_turn.to_string());
205                    moves_since_turn = 0;
206                }
207                movements.push(
208                    robot_direction
209                        .instruction_for_turning_to(new_direction)?
210                        .to_string(),
211                );
212                robot_direction = new_direction;
213            }
214        } else if possible_directions.len() == 4 {
215            robot_position = robot_direction.advance(robot_position);
216            moves_since_turn += 1;
217        } else {
218            return Err(format!(
219                "Invalid possible directions: {}",
220                possible_directions.len()
221            ));
222        }
223    }
224
225    if let Some((segments, sequence)) = find_covering_subsequences(&movements, 3) {
226        let function_a = segments[0];
227        let function_b = segments[1];
228        let function_c = segments[2];
229        let main_routine: Vec<String> = sequence
230            .iter()
231            .map(|&i| ((b'A' + i as u8) as char).to_string())
232            .collect();
233        for input in [&main_routine, function_a, function_b, function_c] {
234            program.input_string(&input.join(","));
235            program.input_string("\n");
236        }
237        program.input_string("n\n");
238        let last_output = program.run_for_output()?;
239        return last_output
240            .iter()
241            .find(|&&value| value > 255)
242            .map(i64::to_string)
243            .ok_or_else(|| "No output > 255 produced".to_string());
244    }
245
246    Err("No output produced".to_string())
247}
248
249fn subsequence_exists<T>(seq: &[T], subseq: &[T]) -> bool
250where
251    T: PartialEq,
252{
253    if subseq.len() > seq.len() {
254        return false;
255    }
256    (0..(seq.len() - subseq.len())).any(|i| seq[i..].starts_with(subseq))
257}
258
259fn find_longest_repeated_subsequence(sequence: &[String]) -> Option<&[String]> {
260    let mut end_min = 0;
261    let mut end_max = sequence.len();
262
263    while end_max > end_min {
264        let end = (end_max + end_min) / 2;
265        if end == end_min {
266            break;
267        } else if subsequence_exists(&sequence[end..], &sequence[0..end]) {
268            end_min = end;
269        } else {
270            end_max = end;
271        }
272    }
273
274    if end_min > 0 {
275        Some(&sequence[0..end_min])
276    } else {
277        None
278    }
279}
280
281fn find_subseq_covering(seq: &[String], subseqs: &[&[String]]) -> Option<VecDeque<usize>> {
282    if seq.is_empty() {
283        Some(VecDeque::new())
284    } else {
285        for (i, subseq) in subseqs.iter().enumerate() {
286            if seq.starts_with(subseq)
287                && let Some(mut subfind) = find_subseq_covering(&seq[subseq.len()..], subseqs)
288            {
289                subfind.push_front(i);
290                return Some(subfind);
291            }
292        }
293
294        None
295    }
296}
297
298fn find_covering_subsequences(
299    seq: &[String],
300    num_subsequences: usize,
301) -> Option<(Vec<&[String]>, VecDeque<usize>)> {
302    fn fill_subsequences<'a>(
303        seq: &'a [String],
304        num_subsequences: usize,
305        mut subsequences: Vec<&'a [String]>,
306    ) -> Option<Vec<&'a [String]>> {
307        if seq.is_empty() || subsequences.len() == num_subsequences {
308            Some(subsequences)
309        } else if let Some(prefix) = subsequences.iter().find(|subseq| seq.starts_with(subseq)) {
310            fill_subsequences(&seq[prefix.len()..], num_subsequences, subsequences)
311        } else {
312            let next = find_longest_repeated_subsequence(seq)?;
313            subsequences.push(next);
314            fill_subsequences(&seq[next.len()..], num_subsequences, subsequences)
315        }
316    }
317
318    let mut subsequences: Vec<&[String]> = fill_subsequences(seq, num_subsequences, Vec::new())?;
319
320    while !subsequences[0].is_empty() {
321        if let Some(covering) = find_subseq_covering(seq, &subsequences)
322            && !subsequences.iter().any(|s| s.join(",").len() > 20)
323        {
324            return Some((subsequences, covering));
325        }
326
327        while !subsequences.is_empty() {
328            let i = subsequences.len() - 1;
329            subsequences[i] = subsequences[i].split_last()?.1;
330            if subsequences[subsequences.len() - 1].is_empty() {
331                subsequences.pop();
332            } else {
333                subsequences = fill_subsequences(seq, num_subsequences, subsequences)?;
334                break;
335            }
336        }
337
338        if subsequences.is_empty() {
339            return None;
340        }
341    }
342    None
343}
344
345#[test]
346pub fn tests() {
347    assert_eq!(
348        part1_map(
349            "..#..........
350..#..........
351#######...###
352#.#...#...#.#
353#############
354..#...#...#..
355..#####...^..",
356        ),
357        Ok("76".to_string())
358    );
359
360    test_part_two!("1,330,331,332,109,3546,1101,0,1182,15,1101,1481,0,24,1001,0,0,570,1006,570,36,102,1,571,0,1001,570,-1,570,1001,24,1,24,1105,1,18,1008,571,0,571,1001,15,1,15,1008,15,1481,570,1006,570,14,21102,58,1,0,1106,0,786,1006,332,62,99,21101,0,333,1,21101,0,73,0,1106,0,579,1101,0,0,572,1101,0,0,573,3,574,101,1,573,573,1007,574,65,570,1005,570,151,107,67,574,570,1005,570,151,1001,574,-64,574,1002,574,-1,574,1001,572,1,572,1007,572,11,570,1006,570,165,101,1182,572,127,1002,574,1,0,3,574,101,1,573,573,1008,574,10,570,1005,570,189,1008,574,44,570,1006,570,158,1105,1,81,21102,1,340,1,1106,0,177,21102,1,477,1,1106,0,177,21101,0,514,1,21102,1,176,0,1105,1,579,99,21102,1,184,0,1106,0,579,4,574,104,10,99,1007,573,22,570,1006,570,165,102,1,572,1182,21102,375,1,1,21101,211,0,0,1106,0,579,21101,1182,11,1,21101,0,222,0,1106,0,979,21102,388,1,1,21102,1,233,0,1106,0,579,21101,1182,22,1,21102,1,244,0,1106,0,979,21101,0,401,1,21102,255,1,0,1106,0,579,21101,1182,33,1,21102,266,1,0,1105,1,979,21102,414,1,1,21102,1,277,0,1105,1,579,3,575,1008,575,89,570,1008,575,121,575,1,575,570,575,3,574,1008,574,10,570,1006,570,291,104,10,21102,1,1182,1,21102,1,313,0,1105,1,622,1005,575,327,1102,1,1,575,21101,0,327,0,1106,0,786,4,438,99,0,1,1,6,77,97,105,110,58,10,33,10,69,120,112,101,99,116,101,100,32,102,117,110,99,116,105,111,110,32,110,97,109,101,32,98,117,116,32,103,111,116,58,32,0,12,70,117,110,99,116,105,111,110,32,65,58,10,12,70,117,110,99,116,105,111,110,32,66,58,10,12,70,117,110,99,116,105,111,110,32,67,58,10,23,67,111,110,116,105,110,117,111,117,115,32,118,105,100,101,111,32,102,101,101,100,63,10,0,37,10,69,120,112,101,99,116,101,100,32,82,44,32,76,44,32,111,114,32,100,105,115,116,97,110,99,101,32,98,117,116,32,103,111,116,58,32,36,10,69,120,112,101,99,116,101,100,32,99,111,109,109,97,32,111,114,32,110,101,119,108,105,110,101,32,98,117,116,32,103,111,116,58,32,43,10,68,101,102,105,110,105,116,105,111,110,115,32,109,97,121,32,98,101,32,97,116,32,109,111,115,116,32,50,48,32,99,104,97,114,97,99,116,101,114,115,33,10,94,62,118,60,0,1,0,-1,-1,0,1,0,0,0,0,0,0,1,12,18,0,109,4,2102,1,-3,587,20101,0,0,-1,22101,1,-3,-3,21101,0,0,-2,2208,-2,-1,570,1005,570,617,2201,-3,-2,609,4,0,21201,-2,1,-2,1106,0,597,109,-4,2106,0,0,109,5,2102,1,-4,630,20102,1,0,-2,22101,1,-4,-4,21101,0,0,-3,2208,-3,-2,570,1005,570,781,2201,-4,-3,653,20102,1,0,-1,1208,-1,-4,570,1005,570,709,1208,-1,-5,570,1005,570,734,1207,-1,0,570,1005,570,759,1206,-1,774,1001,578,562,684,1,0,576,576,1001,578,566,692,1,0,577,577,21101,0,702,0,1105,1,786,21201,-1,-1,-1,1106,0,676,1001,578,1,578,1008,578,4,570,1006,570,724,1001,578,-4,578,21102,731,1,0,1105,1,786,1106,0,774,1001,578,-1,578,1008,578,-1,570,1006,570,749,1001,578,4,578,21102,1,756,0,1105,1,786,1105,1,774,21202,-1,-11,1,22101,1182,1,1,21101,0,774,0,1106,0,622,21201,-3,1,-3,1106,0,640,109,-5,2106,0,0,109,7,1005,575,802,21001,576,0,-6,20102,1,577,-5,1106,0,814,21102,1,0,-1,21102,0,1,-5,21102,0,1,-6,20208,-6,576,-2,208,-5,577,570,22002,570,-2,-2,21202,-5,59,-3,22201,-6,-3,-3,22101,1481,-3,-3,2101,0,-3,843,1005,0,863,21202,-2,42,-4,22101,46,-4,-4,1206,-2,924,21102,1,1,-1,1105,1,924,1205,-2,873,21102,35,1,-4,1105,1,924,2101,0,-3,878,1008,0,1,570,1006,570,916,1001,374,1,374,1202,-3,1,895,1101,0,2,0,2101,0,-3,902,1001,438,0,438,2202,-6,-5,570,1,570,374,570,1,570,438,438,1001,578,558,921,21002,0,1,-4,1006,575,959,204,-4,22101,1,-6,-6,1208,-6,59,570,1006,570,814,104,10,22101,1,-5,-5,1208,-5,35,570,1006,570,810,104,10,1206,-1,974,99,1206,-1,974,1101,0,1,575,21102,973,1,0,1105,1,786,99,109,-7,2105,1,0,109,6,21101,0,0,-4,21102,0,1,-3,203,-2,22101,1,-3,-3,21208,-2,82,-1,1205,-1,1030,21208,-2,76,-1,1205,-1,1037,21207,-2,48,-1,1205,-1,1124,22107,57,-2,-1,1205,-1,1124,21201,-2,-48,-2,1106,0,1041,21102,1,-4,-2,1106,0,1041,21101,0,-5,-2,21201,-4,1,-4,21207,-4,11,-1,1206,-1,1138,2201,-5,-4,1059,1202,-2,1,0,203,-2,22101,1,-3,-3,21207,-2,48,-1,1205,-1,1107,22107,57,-2,-1,1205,-1,1107,21201,-2,-48,-2,2201,-5,-4,1090,20102,10,0,-1,22201,-2,-1,-2,2201,-5,-4,1103,1202,-2,1,0,1105,1,1060,21208,-2,10,-1,1205,-1,1162,21208,-2,44,-1,1206,-1,1131,1105,1,989,21101,0,439,1,1106,0,1150,21102,477,1,1,1106,0,1150,21101,0,514,1,21102,1,1149,0,1105,1,579,99,21101,0,1157,0,1106,0,579,204,-2,104,10,99,21207,-3,22,-1,1206,-1,1138,2101,0,-5,1176,1201,-4,0,0,109,-6,2105,1,0,6,13,27,13,6,1,11,1,27,1,11,1,6,1,11,1,27,1,11,1,6,1,11,1,27,1,11,1,6,1,11,1,27,1,11,1,6,1,11,1,27,1,11,1,6,1,11,1,1,9,9,11,9,1,6,1,11,1,1,1,7,1,9,1,7,1,1,1,9,1,6,1,11,13,7,1,7,1,1,1,9,1,6,1,13,1,7,1,1,1,7,1,7,1,1,1,9,1,6,1,13,1,7,1,1,1,5,11,1,1,9,1,6,1,13,1,7,1,1,1,5,1,1,1,9,1,9,1,6,11,3,1,7,1,1,1,5,1,1,1,9,1,1,9,16,1,3,1,7,1,1,1,5,1,1,1,9,1,1,1,24,1,3,1,7,13,7,1,1,1,24,1,3,1,9,1,5,1,1,1,1,1,7,1,1,1,24,1,3,1,9,9,1,1,7,11,16,1,3,1,15,1,3,1,9,1,7,1,12,9,15,1,3,1,9,1,7,1,16,1,19,1,3,1,9,1,7,1,16,1,19,11,3,1,7,1,16,1,23,1,5,1,3,1,7,1,8,9,23,11,7,1,8,1,37,1,11,1,8,1,37,1,11,1,8,1,37,1,11,1,8,1,37,1,11,1,8,1,37,1,11,1,8,1,37,13,8,1,58,1,58,1,58,1,58,1,50,9,50" => "933214".into());
361    test_part_two!("1,330,331,332,109,3080,1101,0,1182,15,1101,0,1403,24,1001,0,0,570,1006,570,36,1002,571,1,0,1001,570,-1,570,1001,24,1,24,1105,1,18,1008,571,0,571,1001,15,1,15,1008,15,1403,570,1006,570,14,21101,58,0,0,1105,1,786,1006,332,62,99,21102,333,1,1,21101,0,73,0,1105,1,579,1102,0,1,572,1101,0,0,573,3,574,101,1,573,573,1007,574,65,570,1005,570,151,107,67,574,570,1005,570,151,1001,574,-64,574,1002,574,-1,574,1001,572,1,572,1007,572,11,570,1006,570,165,101,1182,572,127,101,0,574,0,3,574,101,1,573,573,1008,574,10,570,1005,570,189,1008,574,44,570,1006,570,158,1106,0,81,21102,1,340,1,1105,1,177,21102,477,1,1,1105,1,177,21102,1,514,1,21102,1,176,0,1106,0,579,99,21101,184,0,0,1105,1,579,4,574,104,10,99,1007,573,22,570,1006,570,165,1002,572,1,1182,21101,0,375,1,21102,211,1,0,1105,1,579,21101,1182,11,1,21102,1,222,0,1106,0,979,21101,0,388,1,21102,233,1,0,1105,1,579,21101,1182,22,1,21101,244,0,0,1105,1,979,21101,0,401,1,21101,255,0,0,1106,0,579,21101,1182,33,1,21101,266,0,0,1106,0,979,21101,0,414,1,21102,1,277,0,1105,1,579,3,575,1008,575,89,570,1008,575,121,575,1,575,570,575,3,574,1008,574,10,570,1006,570,291,104,10,21101,1182,0,1,21101,313,0,0,1105,1,622,1005,575,327,1101,1,0,575,21101,327,0,0,1106,0,786,4,438,99,0,1,1,6,77,97,105,110,58,10,33,10,69,120,112,101,99,116,101,100,32,102,117,110,99,116,105,111,110,32,110,97,109,101,32,98,117,116,32,103,111,116,58,32,0,12,70,117,110,99,116,105,111,110,32,65,58,10,12,70,117,110,99,116,105,111,110,32,66,58,10,12,70,117,110,99,116,105,111,110,32,67,58,10,23,67,111,110,116,105,110,117,111,117,115,32,118,105,100,101,111,32,102,101,101,100,63,10,0,37,10,69,120,112,101,99,116,101,100,32,82,44,32,76,44,32,111,114,32,100,105,115,116,97,110,99,101,32,98,117,116,32,103,111,116,58,32,36,10,69,120,112,101,99,116,101,100,32,99,111,109,109,97,32,111,114,32,110,101,119,108,105,110,101,32,98,117,116,32,103,111,116,58,32,43,10,68,101,102,105,110,105,116,105,111,110,115,32,109,97,121,32,98,101,32,97,116,32,109,111,115,116,32,50,48,32,99,104,97,114,97,99,116,101,114,115,33,10,94,62,118,60,0,1,0,-1,-1,0,1,0,0,0,0,0,0,1,20,26,0,109,4,1202,-3,1,587,20102,1,0,-1,22101,1,-3,-3,21101,0,0,-2,2208,-2,-1,570,1005,570,617,2201,-3,-2,609,4,0,21201,-2,1,-2,1106,0,597,109,-4,2106,0,0,109,5,1202,-4,1,630,20101,0,0,-2,22101,1,-4,-4,21102,0,1,-3,2208,-3,-2,570,1005,570,781,2201,-4,-3,653,20102,1,0,-1,1208,-1,-4,570,1005,570,709,1208,-1,-5,570,1005,570,734,1207,-1,0,570,1005,570,759,1206,-1,774,1001,578,562,684,1,0,576,576,1001,578,566,692,1,0,577,577,21101,0,702,0,1105,1,786,21201,-1,-1,-1,1106,0,676,1001,578,1,578,1008,578,4,570,1006,570,724,1001,578,-4,578,21102,1,731,0,1106,0,786,1105,1,774,1001,578,-1,578,1008,578,-1,570,1006,570,749,1001,578,4,578,21101,756,0,0,1105,1,786,1106,0,774,21202,-1,-11,1,22101,1182,1,1,21101,774,0,0,1105,1,622,21201,-3,1,-3,1106,0,640,109,-5,2105,1,0,109,7,1005,575,802,20101,0,576,-6,21002,577,1,-5,1106,0,814,21102,0,1,-1,21101,0,0,-5,21101,0,0,-6,20208,-6,576,-2,208,-5,577,570,22002,570,-2,-2,21202,-5,43,-3,22201,-6,-3,-3,22101,1403,-3,-3,2102,1,-3,843,1005,0,863,21202,-2,42,-4,22101,46,-4,-4,1206,-2,924,21101,0,1,-1,1106,0,924,1205,-2,873,21101,35,0,-4,1106,0,924,1201,-3,0,878,1008,0,1,570,1006,570,916,1001,374,1,374,1201,-3,0,895,1101,2,0,0,1201,-3,0,902,1001,438,0,438,2202,-6,-5,570,1,570,374,570,1,570,438,438,1001,578,558,922,20102,1,0,-4,1006,575,959,204,-4,22101,1,-6,-6,1208,-6,43,570,1006,570,814,104,10,22101,1,-5,-5,1208,-5,39,570,1006,570,810,104,10,1206,-1,974,99,1206,-1,974,1101,0,1,575,21101,0,973,0,1105,1,786,99,109,-7,2105,1,0,109,6,21101,0,0,-4,21101,0,0,-3,203,-2,22101,1,-3,-3,21208,-2,82,-1,1205,-1,1030,21208,-2,76,-1,1205,-1,1037,21207,-2,48,-1,1205,-1,1124,22107,57,-2,-1,1205,-1,1124,21201,-2,-48,-2,1106,0,1041,21102,1,-4,-2,1106,0,1041,21102,1,-5,-2,21201,-4,1,-4,21207,-4,11,-1,1206,-1,1138,2201,-5,-4,1059,1201,-2,0,0,203,-2,22101,1,-3,-3,21207,-2,48,-1,1205,-1,1107,22107,57,-2,-1,1205,-1,1107,21201,-2,-48,-2,2201,-5,-4,1090,20102,10,0,-1,22201,-2,-1,-2,2201,-5,-4,1103,2101,0,-2,0,1106,0,1060,21208,-2,10,-1,1205,-1,1162,21208,-2,44,-1,1206,-1,1131,1105,1,989,21101,0,439,1,1106,0,1150,21102,1,477,1,1106,0,1150,21101,514,0,1,21101,1149,0,0,1106,0,579,99,21101,1157,0,0,1105,1,579,204,-2,104,10,99,21207,-3,22,-1,1206,-1,1138,1201,-5,0,1176,2101,0,-4,0,109,-6,2105,1,0,28,5,38,1,3,1,38,1,3,1,38,1,3,1,38,1,3,1,38,1,3,1,34,9,34,1,3,1,38,1,3,1,38,1,3,1,34,9,34,1,3,1,38,1,3,1,38,1,3,1,34,5,3,5,30,1,11,1,30,1,11,1,30,1,11,1,22,9,11,5,18,1,23,1,18,1,23,1,18,1,23,1,10,7,1,1,19,9,6,1,5,1,1,1,19,1,3,1,3,1,6,1,5,1,1,5,15,1,3,1,3,1,6,1,5,1,5,1,15,1,3,1,3,1,6,11,1,1,1,7,3,5,3,11,6,1,3,1,1,1,1,1,9,1,11,1,5,1,6,1,1,9,7,1,11,1,5,1,6,1,1,1,1,1,1,1,1,1,9,1,11,1,5,1,6,9,1,9,11,7,8,1,1,1,1,1,3,1,30,9,3,1,30,1,3,1,1,1,5,1,30,1,3,1,1,7,30,1,3,1,38,1,3,1,38,1,3,1,38,5,34" => "714866".into());
362
363    let input = include_str!("day17_input.txt");
364    test_part_one!(input => "11140".into());
365    test_part_two!(input => "1113108".into());
366}