day16
This commit is contained in:
		
							parent
							
								
									4ce7184b1e
								
							
						
					
					
						commit
						dc5f488212
					
				
							
								
								
									
										287
									
								
								aoc_2024/src/day16.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										287
									
								
								aoc_2024/src/day16.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,287 @@ | ||||
| use std::{ | ||||
|     cmp::{Ordering, Reverse}, | ||||
|     collections::BinaryHeap, | ||||
| }; | ||||
| 
 | ||||
| use aoc_runner_derive::{aoc, aoc_generator}; | ||||
| use hashbrown::HashSet; | ||||
| 
 | ||||
| #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||||
| enum Cell { | ||||
|     Empty, | ||||
|     Wall, | ||||
| } | ||||
| 
 | ||||
| type Input = ((usize, usize), (usize, usize), Vec<Vec<Cell>>); | ||||
| 
 | ||||
| #[aoc_generator(day16)] | ||||
| fn parse(input: &str) -> Input { | ||||
|     let mut pos = (0, 0); | ||||
|     let mut end = (0, 0); | ||||
|     let map = input | ||||
|         .lines() | ||||
|         .enumerate() | ||||
|         .map(|(y, line)| { | ||||
|             line.chars() | ||||
|                 .enumerate() | ||||
|                 .map(|(x, c)| match c { | ||||
|                     '#' => Cell::Wall, | ||||
|                     '.' => Cell::Empty, | ||||
|                     'E' => { | ||||
|                         end = (x, y); | ||||
|                         Cell::Empty | ||||
|                     } | ||||
|                     'S' => { | ||||
|                         pos = (x, y); | ||||
|                         Cell::Empty | ||||
|                     } | ||||
|                     _ => unreachable!(), | ||||
|                 }) | ||||
|                 .collect() | ||||
|         }) | ||||
|         .collect(); | ||||
|     (pos, end, map) | ||||
| } | ||||
| 
 | ||||
| #[aoc(day16, part1)] | ||||
| fn part1(input: &Input) -> i64 { | ||||
|     let start = (input.0 .0 as i64, input.0 .1 as i64); | ||||
|     let end = (input.1 .0 as i64, input.1 .1 as i64); | ||||
|     let map = input.2.clone(); | ||||
|     let w = map[0].len(); | ||||
|     let h = map.len(); | ||||
|     let mut d = vec![vec![[i64::MAX; 4]; w]; h]; | ||||
| 
 | ||||
|     #[allow(clippy::type_complexity)] | ||||
|     let mut queue: BinaryHeap<Reverse<(i64, i64, i64, i64, i64)>> = BinaryHeap::new(); | ||||
|     d[start.1 as usize][start.0 as usize][1] = 0; | ||||
|     queue.push(Reverse((0, start.0, start.1, 1, 0))); | ||||
| 
 | ||||
|     while let Some(Reverse((dist, pos_x, pos_y, dir_x, dir_y))) = queue.pop() { | ||||
|         let dir_num = match (dir_x, dir_y) { | ||||
|             (0, -1) => 0, | ||||
|             (1, 0) => 1, | ||||
|             (0, 1) => 2, | ||||
|             (-1, 0) => 3, | ||||
|             _ => unreachable!(), | ||||
|         }; | ||||
| 
 | ||||
|         if d[pos_y as usize][pos_x as usize][dir_num] < dist { | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         if (pos_x, pos_y) == end { | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         if map[(pos_y + dir_y) as usize][(pos_x + dir_x) as usize] == Cell::Empty { | ||||
|             let dist_next = &mut d[(pos_y + dir_y) as usize][(pos_x + dir_x) as usize][dir_num]; | ||||
|             if (dist + 1).cmp(dist_next) == Ordering::Less { | ||||
|                 *dist_next = dist + 1; | ||||
|                 queue.push(Reverse(( | ||||
|                     *dist_next, | ||||
|                     pos_x + dir_x, | ||||
|                     pos_y + dir_y, | ||||
|                     dir_x, | ||||
|                     dir_y, | ||||
|                 ))); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         { | ||||
|             let dist_next = &mut d[pos_y as usize][pos_x as usize][(dir_num + 3) % 4]; | ||||
|             if (dist + 1000).cmp(dist_next) == Ordering::Less { | ||||
|                 *dist_next = dist + 1000; | ||||
|                 queue.push(Reverse((*dist_next, pos_x, pos_y, dir_y, -dir_x))); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         { | ||||
|             let dist_next = &mut d[pos_y as usize][pos_x as usize][(dir_num + 1) % 4]; | ||||
|             if (dist + 1000).cmp(dist_next) == Ordering::Less { | ||||
|                 *dist_next = dist + 1000; | ||||
|                 queue.push(Reverse((*dist_next, pos_x, pos_y, -dir_y, dir_x))); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     *d[end.1 as usize][end.0 as usize].iter().min().unwrap() | ||||
| } | ||||
| 
 | ||||
| #[aoc(day16, part2)] | ||||
| fn part2(input: &Input) -> i64 { | ||||
|     let start = (input.0 .0 as i64, input.0 .1 as i64); | ||||
|     let end = (input.1 .0 as i64, input.1 .1 as i64); | ||||
|     let map = input.2.clone(); | ||||
|     let w = map[0].len(); | ||||
|     let h = map.len(); | ||||
|     let mut d = vec![vec![[i64::MAX; 4]; w]; h]; | ||||
|     let mut b = vec![vec![[vec![], vec![], vec![], vec![]]; w]; h]; | ||||
| 
 | ||||
|     #[allow(clippy::type_complexity)] | ||||
|     let mut queue: BinaryHeap<Reverse<(i64, i64, i64, i64, i64)>> = BinaryHeap::new(); | ||||
|     d[start.1 as usize][start.0 as usize][1] = 0; | ||||
|     queue.push(Reverse((0, start.0, start.1, 1, 0))); | ||||
| 
 | ||||
|     while let Some(Reverse((dist, pos_x, pos_y, dir_x, dir_y))) = queue.pop() { | ||||
|         let dir_num = match (dir_x, dir_y) { | ||||
|             (0, -1) => 0, | ||||
|             (1, 0) => 1, | ||||
|             (0, 1) => 2, | ||||
|             (-1, 0) => 3, | ||||
|             _ => unreachable!(), | ||||
|         }; | ||||
| 
 | ||||
|         if d[pos_y as usize][pos_x as usize][dir_num] < dist { | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         if (pos_x, pos_y) == end { | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         if map[(pos_y + dir_y) as usize][(pos_x + dir_x) as usize] == Cell::Empty { | ||||
|             let dist_next = &mut d[(pos_y + dir_y) as usize][(pos_x + dir_x) as usize][dir_num]; | ||||
|             let back_next = &mut b[(pos_y + dir_y) as usize][(pos_x + dir_x) as usize][dir_num]; | ||||
|             if (dist + 1).cmp(dist_next) == Ordering::Less { | ||||
|                 *dist_next = dist + 1; | ||||
|                 back_next.clear(); | ||||
|                 back_next.push((pos_x, pos_y, dir_num)); | ||||
|                 queue.push(Reverse(( | ||||
|                     *dist_next, | ||||
|                     pos_x + dir_x, | ||||
|                     pos_y + dir_y, | ||||
|                     dir_x, | ||||
|                     dir_y, | ||||
|                 ))); | ||||
|             } else if (dist + 1).cmp(dist_next) == Ordering::Equal { | ||||
|                 back_next.push((pos_x, pos_y, dir_num)); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         { | ||||
|             let dist_next = &mut d[pos_y as usize][pos_x as usize][(dir_num + 3) % 4]; | ||||
|             let back_next = &mut b[pos_y as usize][pos_x as usize][(dir_num + 3) % 4]; | ||||
|             if (dist + 1000).cmp(dist_next) == Ordering::Less { | ||||
|                 *dist_next = dist + 1000; | ||||
|                 back_next.clear(); | ||||
|                 back_next.push((pos_x, pos_y, dir_num)); | ||||
|                 queue.push(Reverse((*dist_next, pos_x, pos_y, dir_y, -dir_x))); | ||||
|             } else if (dist + 1000).cmp(dist_next) == Ordering::Equal { | ||||
|                 back_next.push((pos_x, pos_y, dir_num)); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         { | ||||
|             let dist_next = &mut d[pos_y as usize][pos_x as usize][(dir_num + 1) % 4]; | ||||
|             let back_next = &mut b[pos_y as usize][pos_x as usize][(dir_num + 1) % 4]; | ||||
|             if (dist + 1000).cmp(dist_next) == Ordering::Less { | ||||
|                 *dist_next = dist + 1000; | ||||
|                 back_next.clear(); | ||||
|                 back_next.push((pos_x, pos_y, dir_num)); | ||||
|                 queue.push(Reverse((*dist_next, pos_x, pos_y, -dir_y, dir_x))); | ||||
|             } else if (dist + 1000).cmp(dist_next) == Ordering::Equal { | ||||
|                 back_next.push((pos_x, pos_y, dir_num)); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     let mut visited = HashSet::new(); | ||||
|     let dist_min = *d[end.1 as usize][end.0 as usize].iter().min().unwrap(); | ||||
|     let mut stack = vec![]; | ||||
|     d[end.1 as usize][end.0 as usize] | ||||
|         .iter() | ||||
|         .enumerate() | ||||
|         .for_each(|(i, d)| { | ||||
|             if *d == dist_min { | ||||
|                 stack.push((end.0, end.1, i)); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|     while let Some((pos_x, pos_y, dir_num)) = stack.pop() { | ||||
|         visited.insert((pos_x, pos_y)); | ||||
|         stack.append(&mut b[pos_y as usize][pos_x as usize][dir_num]); | ||||
|     } | ||||
| 
 | ||||
|     visited.len() as i64 | ||||
| } | ||||
| 
 | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use super::*; | ||||
| 
 | ||||
|     #[test] | ||||
|     fn part1_example() { | ||||
|         assert_eq!( | ||||
|             part1(&parse( | ||||
|                 "###############
 | ||||
| #.......#....E# | ||||
| #.#.###.#.###.# | ||||
| #.....#.#...#.# | ||||
| #.###.#####.#.# | ||||
| #.#.#.......#.# | ||||
| #.#.#####.###.# | ||||
| #...........#.# | ||||
| ###.#.#####.#.# | ||||
| #...#.....#.#.# | ||||
| #.#.#.###.#.#.# | ||||
| #.....#...#.#.# | ||||
| #.###.#.#.#.#.# | ||||
| #S..#.....#...# | ||||
| ###############" | ||||
|             )), | ||||
|             7036 | ||||
|         ); | ||||
|         assert_eq!( | ||||
|             part1(&parse(include_str!("../input/2024/day16.txt"))), | ||||
|             85420 | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn part2_example() { | ||||
|         assert_eq!( | ||||
|             part2(&parse( | ||||
|                 "###############
 | ||||
| #.......#....E# | ||||
| #.#.###.#.###.# | ||||
| #.....#.#...#.# | ||||
| #.###.#####.#.# | ||||
| #.#.#.......#.# | ||||
| #.#.#####.###.# | ||||
| #...........#.# | ||||
| ###.#.#####.#.# | ||||
| #...#.....#.#.# | ||||
| #.#.#.###.#.#.# | ||||
| #.....#...#.#.# | ||||
| #.###.#.#.#.#.# | ||||
| #S..#.....#...# | ||||
| ###############" | ||||
|             )), | ||||
|             45 | ||||
|         ); | ||||
|         assert_eq!( | ||||
|             part2(&parse( | ||||
|                 "#################
 | ||||
| #...#...#...#..E# | ||||
| #.#.#.#.#.#.#.#.# | ||||
| #.#.#.#...#...#.# | ||||
| #.#.#.#.###.#.#.# | ||||
| #...#.#.#.....#.# | ||||
| #.#.#.#.#.#####.# | ||||
| #.#...#.#.#.....# | ||||
| #.#.#####.#.###.# | ||||
| #.#.#.......#...# | ||||
| #.#.###.#####.### | ||||
| #.#.#...#.....#.# | ||||
| #.#.#.#####.###.# | ||||
| #.#.#.........#.# | ||||
| #.#.#.#########.# | ||||
| #S#.............# | ||||
| #################" | ||||
|             )), | ||||
|             64 | ||||
|         ); | ||||
|         assert_eq!(part2(&parse(include_str!("../input/2024/day16.txt"))), 492); | ||||
|     } | ||||
| } | ||||
| @ -5,6 +5,7 @@ mod day12; | ||||
| mod day13; | ||||
| mod day14; | ||||
| mod day15; | ||||
| mod day16; | ||||
| mod day2; | ||||
| mod day3; | ||||
| mod day4; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Jan-Bulthuis
						Jan-Bulthuis