y2024d10
This commit is contained in:
		
							
								
								
									
										41
									
								
								y2024/resources/10_input.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								y2024/resources/10_input.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | |||||||
|  | 21056789894321015012980123498787601045687 | ||||||
|  | 32346543765601156703474544567896012138796 | ||||||
|  | 10107632659892349821563678989345643029655 | ||||||
|  | 23218101256781015430412101071234754910544 | ||||||
|  | 14569870345432016321003012560109867801033 | ||||||
|  | 05678963256789127879854303456078105932122 | ||||||
|  | 18723450109898038910765210010563254541001 | ||||||
|  | 69011201298788945125898998323454569679852 | ||||||
|  | 78760345345654876034787677401235378089760 | ||||||
|  | 89456896012503876965014586512765432123601 | ||||||
|  | 32387987003412965872123298703890101984512 | ||||||
|  | 01291876121101234989456107654965278854603 | ||||||
|  | 00180145030980325678327890217874369763254 | ||||||
|  | 14343232145671013454310691307893454610169 | ||||||
|  | 23432165430110302169234582456732108905678 | ||||||
|  | 96547078923231231078105673454321097214523 | ||||||
|  | 87678432214348940987017894765870986341014 | ||||||
|  | 96589541009857654320123765891963475498765 | ||||||
|  | 01434630111766789010432143210452560167876 | ||||||
|  | 32345721210951999016549054789301001456965 | ||||||
|  | 21076890129810878321678945643219812332109 | ||||||
|  | 78789001234723765430321238756106734323458 | ||||||
|  | 09654160345654210389210109987005125010767 | ||||||
|  | 12323271657601345678780125678014056541893 | ||||||
|  | 25414987798542343456690034329123987932012 | ||||||
|  | 56905677810439652987501145016510345801101 | ||||||
|  | 67856298923128721987432156987421256789210 | ||||||
|  | 22347107654098910876543087870330107654301 | ||||||
|  | 11298231012347654305678898981278798987652 | ||||||
|  | 00109545691056763211219767874569678690343 | ||||||
|  | 12065456783345894320105656913450569541289 | ||||||
|  | 43874321092132101899234541002321256632176 | ||||||
|  | 54930010561001234788765432211056746789045 | ||||||
|  | 67821123472390545654123101347849839874330 | ||||||
|  | 78934010589487698763034567456931028765221 | ||||||
|  | 67785697696590101672105698741022210540100 | ||||||
|  | 58696788787781234589789789012013307632101 | ||||||
|  | 49545459810170301075674654323454458989032 | ||||||
|  | 30432365923965432165463210498569567976543 | ||||||
|  | 21021876854876523678354112347678678875301 | ||||||
|  | 30010966763987014589210001456565589765432 | ||||||
							
								
								
									
										20
									
								
								y2024/src/bin/d10.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								y2024/src/bin/d10.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | |||||||
|  | use std::fs; | ||||||
|  |  | ||||||
|  | use y2024::days::d10; | ||||||
|  |  | ||||||
|  | fn main() { | ||||||
|  |     part1(); | ||||||
|  |     part2(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | fn part1() { | ||||||
|  |     let root = env!("CARGO_MANIFEST_DIR"); | ||||||
|  |     let content = fs::read_to_string(format!("{root}/resources/10_input.txt")).unwrap(); | ||||||
|  |     println!("{}", d10::process_part1(&content)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | fn part2() { | ||||||
|  |     let root = env!("CARGO_MANIFEST_DIR"); | ||||||
|  |     let content = fs::read_to_string(format!("{root}/resources/10_input.txt")).unwrap(); | ||||||
|  |     println!("{}", d10::process_part2(&content)); | ||||||
|  | } | ||||||
							
								
								
									
										332
									
								
								y2024/src/days/d10.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										332
									
								
								y2024/src/days/d10.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,332 @@ | |||||||
|  | use itertools::Itertools; | ||||||
|  |  | ||||||
|  | #[derive(Debug, Clone, Copy, Default, Hash, PartialEq, Eq)] | ||||||
|  | struct TrailTile { | ||||||
|  |     coords: (i32, i32), | ||||||
|  |     height: u8, | ||||||
|  |     up: Option<bool>, | ||||||
|  |     down: Option<bool>, | ||||||
|  |     left: Option<bool>, | ||||||
|  |     right: Option<bool>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl TrailTile { | ||||||
|  |     fn get_neighbors(&self, map: &[Vec<TrailTile>]) -> Vec<TrailTile> { | ||||||
|  |         let mut neighbors = Vec::new(); | ||||||
|  |         if let Some(up) = self.up { | ||||||
|  |             if up { | ||||||
|  |                 let neighbor = map[self.coords.1 as usize - 1][self.coords.0 as usize]; | ||||||
|  |                 if neighbor.height == self.height + 1 { | ||||||
|  |                     neighbors.push(neighbor); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if let Some(down) = self.down { | ||||||
|  |             if down { | ||||||
|  |                 let neighbor = map[self.coords.1 as usize + 1][self.coords.0 as usize]; | ||||||
|  |                 if neighbor.height == self.height + 1 { | ||||||
|  |                     neighbors.push(neighbor); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if let Some(left) = self.left { | ||||||
|  |             if left { | ||||||
|  |                 let neighbor = map[self.coords.1 as usize][self.coords.0 as usize - 1]; | ||||||
|  |                 if neighbor.height == self.height + 1 { | ||||||
|  |                     neighbors.push(neighbor); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if let Some(right) = self.right { | ||||||
|  |             if right { | ||||||
|  |                 let neighbor = map[self.coords.1 as usize][self.coords.0 as usize + 1]; | ||||||
|  |                 if neighbor.height == self.height + 1 { | ||||||
|  |                     neighbors.push(neighbor); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         neighbors | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub fn process_part1(input: &str) -> i32 { | ||||||
|  |     let map = input | ||||||
|  |         .lines() | ||||||
|  |         .enumerate() | ||||||
|  |         .map(|(yidx, line)| { | ||||||
|  |             line.as_bytes() | ||||||
|  |                 .iter() | ||||||
|  |                 .enumerate() | ||||||
|  |                 .map(|(xidx, &height)| TrailTile { | ||||||
|  |                     coords: (xidx as i32, yidx as i32), | ||||||
|  |                     height, | ||||||
|  |                     ..Default::default() | ||||||
|  |                 }) | ||||||
|  |                 .collect_vec() | ||||||
|  |         }) | ||||||
|  |         .collect_vec(); | ||||||
|  |     let mut updated_map = Vec::new(); | ||||||
|  |     let mut trailheads = Vec::new(); | ||||||
|  |     for row in map.iter() { | ||||||
|  |         let mut new_row = Vec::new(); | ||||||
|  |         for tile in row { | ||||||
|  |             let up = match map.get((tile.coords.1 - 1) as usize) { | ||||||
|  |                 Some(row) => { | ||||||
|  |                     let up = row[tile.coords.0 as usize]; | ||||||
|  |                     Some(up.height == tile.height + 1) | ||||||
|  |                 } | ||||||
|  |                 None => None, | ||||||
|  |             }; | ||||||
|  |             let down = match map.get((tile.coords.1 + 1) as usize) { | ||||||
|  |                 Some(row) => { | ||||||
|  |                     let down = row[tile.coords.0 as usize]; | ||||||
|  |                     Some(down.height == tile.height + 1) | ||||||
|  |                 } | ||||||
|  |                 None => None, | ||||||
|  |             }; | ||||||
|  |             let left = map[tile.coords.1 as usize] | ||||||
|  |                 .get((tile.coords.0 - 1) as usize) | ||||||
|  |                 .map(|left| left.height == tile.height + 1); | ||||||
|  |             let right = map[tile.coords.1 as usize] | ||||||
|  |                 .get((tile.coords.0 + 1) as usize) | ||||||
|  |                 .map(|right| right.height == tile.height + 1); | ||||||
|  |             let tile = TrailTile { | ||||||
|  |                 up, | ||||||
|  |                 down, | ||||||
|  |                 left, | ||||||
|  |                 right, | ||||||
|  |                 ..*tile | ||||||
|  |             }; | ||||||
|  |             if tile.height == b'0' { | ||||||
|  |                 trailheads.push(tile); | ||||||
|  |             } | ||||||
|  |             //print!( | ||||||
|  |             //    "{}: {}, {}      ", | ||||||
|  |             //    tile.height as char, tile.coords.0, tile.coords.1 | ||||||
|  |             //); | ||||||
|  |             new_row.push(tile); | ||||||
|  |         } | ||||||
|  |         //println!(); | ||||||
|  |         updated_map.push(new_row); | ||||||
|  |     } | ||||||
|  |     let mut res = 0; | ||||||
|  |     //println!("0 {trailheads:?}"); | ||||||
|  |     for trailhead in trailheads { | ||||||
|  |         let mut neighbors = trailhead.get_neighbors(&updated_map); | ||||||
|  |         //println!("1 {neighbors:?}"); | ||||||
|  |         for _idx in 2..=9 { | ||||||
|  |             //println!("{idx}"); | ||||||
|  |             if neighbors.is_empty() { | ||||||
|  |                 //println!("empty"); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             let inner_neighbors = neighbors.clone(); | ||||||
|  |             neighbors.clear(); | ||||||
|  |             for neighbor in inner_neighbors { | ||||||
|  |                 neighbors.extend_from_slice(&neighbor.get_neighbors(&updated_map)); | ||||||
|  |             } | ||||||
|  |             //println!("{idx} {neighbors:?}"); | ||||||
|  |         } | ||||||
|  |         res += neighbors.iter().unique().count(); | ||||||
|  |     } | ||||||
|  |     res as i32 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub fn process_part2(input: &str) -> i32 { | ||||||
|  |     let map = input | ||||||
|  |         .lines() | ||||||
|  |         .enumerate() | ||||||
|  |         .map(|(yidx, line)| { | ||||||
|  |             line.as_bytes() | ||||||
|  |                 .iter() | ||||||
|  |                 .enumerate() | ||||||
|  |                 .map(|(xidx, &height)| TrailTile { | ||||||
|  |                     coords: (xidx as i32, yidx as i32), | ||||||
|  |                     height, | ||||||
|  |                     ..Default::default() | ||||||
|  |                 }) | ||||||
|  |                 .collect_vec() | ||||||
|  |         }) | ||||||
|  |         .collect_vec(); | ||||||
|  |     let mut updated_map = Vec::new(); | ||||||
|  |     let mut trailheads = Vec::new(); | ||||||
|  |     for row in map.iter() { | ||||||
|  |         let mut new_row = Vec::new(); | ||||||
|  |         for tile in row { | ||||||
|  |             let up = match map.get((tile.coords.1 - 1) as usize) { | ||||||
|  |                 Some(row) => { | ||||||
|  |                     let up = row[tile.coords.0 as usize]; | ||||||
|  |                     Some(up.height == tile.height + 1) | ||||||
|  |                 } | ||||||
|  |                 None => None, | ||||||
|  |             }; | ||||||
|  |             let down = match map.get((tile.coords.1 + 1) as usize) { | ||||||
|  |                 Some(row) => { | ||||||
|  |                     let down = row[tile.coords.0 as usize]; | ||||||
|  |                     Some(down.height == tile.height + 1) | ||||||
|  |                 } | ||||||
|  |                 None => None, | ||||||
|  |             }; | ||||||
|  |             let left = map[tile.coords.1 as usize] | ||||||
|  |                 .get((tile.coords.0 - 1) as usize) | ||||||
|  |                 .map(|left| left.height == tile.height + 1); | ||||||
|  |             let right = map[tile.coords.1 as usize] | ||||||
|  |                 .get((tile.coords.0 + 1) as usize) | ||||||
|  |                 .map(|right| right.height == tile.height + 1); | ||||||
|  |             let tile = TrailTile { | ||||||
|  |                 up, | ||||||
|  |                 down, | ||||||
|  |                 left, | ||||||
|  |                 right, | ||||||
|  |                 ..*tile | ||||||
|  |             }; | ||||||
|  |             if tile.height == b'0' { | ||||||
|  |                 trailheads.push(tile); | ||||||
|  |             } | ||||||
|  |             //print!( | ||||||
|  |             //    "{}: {}, {}      ", | ||||||
|  |             //    tile.height as char, tile.coords.0, tile.coords.1 | ||||||
|  |             //); | ||||||
|  |             new_row.push(tile); | ||||||
|  |         } | ||||||
|  |         //println!(); | ||||||
|  |         updated_map.push(new_row); | ||||||
|  |     } | ||||||
|  |     let mut res = 0; | ||||||
|  |     //println!("0 {trailheads:?}"); | ||||||
|  |     for trailhead in trailheads { | ||||||
|  |         let mut neighbors = trailhead.get_neighbors(&updated_map); | ||||||
|  |         //println!("1 {neighbors:?}"); | ||||||
|  |         for _idx in 2..=9 { | ||||||
|  |             //println!("{idx}"); | ||||||
|  |             if neighbors.is_empty() { | ||||||
|  |                 //println!("empty"); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             let inner_neighbors = neighbors.clone(); | ||||||
|  |             neighbors.clear(); | ||||||
|  |             for neighbor in inner_neighbors { | ||||||
|  |                 neighbors.extend_from_slice(&neighbor.get_neighbors(&updated_map)); | ||||||
|  |             } | ||||||
|  |             //println!("{idx} {neighbors:?}"); | ||||||
|  |         } | ||||||
|  |         res += neighbors.len(); | ||||||
|  |     } | ||||||
|  |     res as i32 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[cfg(test)] | ||||||
|  | mod tests { | ||||||
|  |     use super::*; | ||||||
|  |  | ||||||
|  |     const INPUT_SMALL: &str = "0123 | ||||||
|  | 1234 | ||||||
|  | 8765 | ||||||
|  | 9876"; | ||||||
|  |  | ||||||
|  |     const INPUT_LARGE: &str = "89010123 | ||||||
|  | 78121874 | ||||||
|  | 87430965 | ||||||
|  | 96549874 | ||||||
|  | 45678903 | ||||||
|  | 32019012 | ||||||
|  | 01329801 | ||||||
|  | 10456732"; | ||||||
|  |  | ||||||
|  |     const INPUT_SIMPLIFIED_1: &str = "...0... | ||||||
|  | ...1... | ||||||
|  | ...2... | ||||||
|  | 6543456 | ||||||
|  | 7.....7 | ||||||
|  | 8.....8 | ||||||
|  | 9.....9"; | ||||||
|  |     const INPUT_SIMPLIFIED_2: &str = "..90..9 | ||||||
|  | ...1.98 | ||||||
|  | ...2..7 | ||||||
|  | 6543456 | ||||||
|  | 765.987 | ||||||
|  | 876.... | ||||||
|  | 987...."; | ||||||
|  |     const INPUT_SIMPLIFIED_3: &str = "10..9.. | ||||||
|  | 2...8.. | ||||||
|  | 3...7.. | ||||||
|  | 4567654 | ||||||
|  | ...8..3 | ||||||
|  | ...9..2 | ||||||
|  | .....01"; | ||||||
|  |  | ||||||
|  |     const INPUT_SIMPLIFIED_4: &str = ".....0. | ||||||
|  | ..4321. | ||||||
|  | ..5..2. | ||||||
|  | ..6543. | ||||||
|  | ..7..4. | ||||||
|  | ..8765. | ||||||
|  | ..9...."; | ||||||
|  |  | ||||||
|  |     const INPUT_SIMPLIFIED_5: &str = "012345 | ||||||
|  | 123456 | ||||||
|  | 234567 | ||||||
|  | 345678 | ||||||
|  | 4.6789 | ||||||
|  | 56789."; | ||||||
|  |  | ||||||
|  |     #[test] | ||||||
|  |     fn part1_small() { | ||||||
|  |         let result = process_part1(INPUT_SMALL); | ||||||
|  |         assert_eq!(result, 1); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     #[test] | ||||||
|  |     fn part1_large() { | ||||||
|  |         let result = process_part1(INPUT_LARGE); | ||||||
|  |         assert_eq!(result, 36); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     #[test] | ||||||
|  |     fn part1_simplified_1() { | ||||||
|  |         let result = process_part1(INPUT_SIMPLIFIED_1); | ||||||
|  |         assert_eq!(result, 2); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     #[test] | ||||||
|  |     fn part1_simplified_2() { | ||||||
|  |         let result = process_part1(INPUT_SIMPLIFIED_2); | ||||||
|  |         assert_eq!(result, 4); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     #[test] | ||||||
|  |     fn part1_simplified_3() { | ||||||
|  |         let result = process_part1(INPUT_SIMPLIFIED_3); | ||||||
|  |         assert_eq!(result, 3); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     #[test] | ||||||
|  |     fn part2_small() { | ||||||
|  |         let result = process_part2(INPUT_SMALL); | ||||||
|  |         assert_eq!(result, 16); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     #[test] | ||||||
|  |     fn part2_large() { | ||||||
|  |         let result = process_part2(INPUT_LARGE); | ||||||
|  |         assert_eq!(result, 81); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     #[test] | ||||||
|  |     fn part2_simplified_2() { | ||||||
|  |         let result = process_part2(INPUT_SIMPLIFIED_2); | ||||||
|  |         assert_eq!(result, 13); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     #[test] | ||||||
|  |     fn part2_simplified_4() { | ||||||
|  |         let result = process_part2(INPUT_SIMPLIFIED_4); | ||||||
|  |         assert_eq!(result, 3); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     #[test] | ||||||
|  |     fn part2_simplified_5() { | ||||||
|  |         let result = process_part2(INPUT_SIMPLIFIED_5); | ||||||
|  |         assert_eq!(result, 227); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -7,3 +7,5 @@ pub mod d6; | |||||||
| pub mod d7; | pub mod d7; | ||||||
| pub mod d8; | pub mod d8; | ||||||
| pub mod d9; | pub mod d9; | ||||||
|  |  | ||||||
|  | pub mod d10; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user