diff --git a/2025/day-02/src/part1.rs b/2025/day-02/src/part1.rs index 260e5fb..e12de30 100644 --- a/2025/day-02/src/part1.rs +++ b/2025/day-02/src/part1.rs @@ -7,7 +7,7 @@ struct Id(usize); impl FromStr for Id { type Err = String; fn from_str(s: &str) -> std::result::Result { - let val = s.parse().unwrap(); + let val = s.parse::().map_err(|e| e.to_string())?; Ok(Self(val)) } } @@ -35,15 +35,20 @@ impl Range { fn has_repeating_sequence(num: usize) -> bool { let s = num.to_string(); let len = s.len(); - len.is_multiple_of(2) && s[0..len / 2].repeat(2) == s + (1..=len / 2).any(|pattern_len| { + let repeats = len / pattern_len; + repeats >= 2 + && len.is_multiple_of(pattern_len) + && s[0..pattern_len].repeat(len / pattern_len) == s + }) } impl FromStr for Range { type Err = String; fn from_str(s: &str) -> std::result::Result { let mut trimmed = s.trim().split('-'); - let start = trimmed.next().unwrap().parse().unwrap(); - let end = trimmed.next_back().unwrap().parse().unwrap(); + let start = trimmed.next().unwrap_or_default().parse()?; + let end = trimmed.next_back().unwrap_or_default().parse()?; Ok(Self { start, end }) } } @@ -58,6 +63,9 @@ pub fn process(input: &str) -> Result { .map(Range::from_str) .flat_map(|range| range.unwrap().find_invalid()) .map(|x| x.0) + .inspect(|x| { + dbg!(x); + }) .sum(); Ok(result) } diff --git a/2025/day-02/src/part2.rs b/2025/day-02/src/part2.rs index ede34a7..97dc477 100644 --- a/2025/day-02/src/part2.rs +++ b/2025/day-02/src/part2.rs @@ -1,23 +1,94 @@ use miette::Result; +use std::str::FromStr; + +#[derive(Debug)] +struct Id(usize); + +impl FromStr for Id { + type Err = String; + fn from_str(s: &str) -> std::result::Result { + let val = s.parse::().map_err(|e| e.to_string())?; + Ok(Self(val)) + } +} + +#[derive(Debug)] +struct Range { + start: Id, + end: Id, +} + +impl Range { + fn find_invalid(&self) -> Vec { + (self.start.0..=self.end.0) + .filter_map(|x| { + if has_repeating_sequence(x) { + Some(Id(x)) + } else { + None + } + }) + .collect() + } +} + +fn has_repeating_sequence(num: usize) -> bool { + let s = num.to_string(); + let len = s.len(); + (1..=len / 2).any(|pattern_len| { + len.is_multiple_of(pattern_len) && s[0..pattern_len].repeat(len / pattern_len) == s + }) +} + +impl FromStr for Range { + type Err = String; + fn from_str(s: &str) -> std::result::Result { + let mut trimmed = s.trim().split('-'); + let start = trimmed.next().unwrap_or_default().parse()?; + let end = trimmed.next_back().unwrap_or_default().parse()?; + Ok(Self { start, end }) + } +} #[tracing::instrument] #[allow(clippy::missing_panics_doc)] #[allow(clippy::missing_errors_doc)] pub fn process(input: &str) -> Result { - todo!("day xx - part 2"); - Ok(0) + let result = input + .trim() + .split(',') + .map(Range::from_str) + .flat_map(|range| range.unwrap().find_invalid()) + .map(|x| x.0) + .sum(); + Ok(result) } #[cfg(test)] mod tests { use super::*; + use rstest::rstest; #[test] fn test_process() -> Result<()> { - let input = ""; - todo!("haven't built test yet"); - let result = 0; + let input = "11-22,95-115,998-1012,1188511880-1188511890,222220-222224,1698522-1698528,446443-446449,38593856-38593862,565653-565659,824824821-824824827,2121212118-2121212124"; + let result = 4_174_379_265; assert_eq!(process(input)?, result); Ok(()) } + + #[rstest] + #[case(11)] + #[case(22)] + #[case(1010)] + #[case(1_188_511_885)] + #[case(222_222)] + #[case(446_446)] + #[case(38_593_859)] + #[case(111)] + #[case(222)] + #[case(222_222_222)] + fn repeating(#[case] num: usize) { + assert!(has_repeating_sequence(num)); + } }