From 64cb7fb37029d91fe28ef740e2e30ca8ce3699f8 Mon Sep 17 00:00:00 2001 From: Fabian Schmidt Date: Tue, 10 Dec 2024 10:32:05 +0100 Subject: [PATCH] y2024d10 --- y2024/resources/10_input.txt | 41 +++++ y2024/src/bin/d10.rs | 20 +++ y2024/src/days/d10.rs | 332 +++++++++++++++++++++++++++++++++++ y2024/src/days/mod.rs | 2 + 4 files changed, 395 insertions(+) create mode 100644 y2024/resources/10_input.txt create mode 100644 y2024/src/bin/d10.rs create mode 100644 y2024/src/days/d10.rs diff --git a/y2024/resources/10_input.txt b/y2024/resources/10_input.txt new file mode 100644 index 0000000..c0caf6e --- /dev/null +++ b/y2024/resources/10_input.txt @@ -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 diff --git a/y2024/src/bin/d10.rs b/y2024/src/bin/d10.rs new file mode 100644 index 0000000..3b18417 --- /dev/null +++ b/y2024/src/bin/d10.rs @@ -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)); +} diff --git a/y2024/src/days/d10.rs b/y2024/src/days/d10.rs new file mode 100644 index 0000000..34365c5 --- /dev/null +++ b/y2024/src/days/d10.rs @@ -0,0 +1,332 @@ +use itertools::Itertools; + +#[derive(Debug, Clone, Copy, Default, Hash, PartialEq, Eq)] +struct TrailTile { + coords: (i32, i32), + height: u8, + up: Option, + down: Option, + left: Option, + right: Option, +} + +impl TrailTile { + fn get_neighbors(&self, map: &[Vec]) -> Vec { + 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); + } +} diff --git a/y2024/src/days/mod.rs b/y2024/src/days/mod.rs index 68906bd..bfc2f40 100644 --- a/y2024/src/days/mod.rs +++ b/y2024/src/days/mod.rs @@ -7,3 +7,5 @@ pub mod d6; pub mod d7; pub mod d8; pub mod d9; + +pub mod d10;