use nom::IResult; use std::ops::RangeInclusive; pub fn process_part_1(input: &str) -> usize { let (_, assignments) = section_assignments(input).unwrap(); assignments .iter() .filter(|(a, b)| range_contains(a, b) || range_contains(b, a)) .count() } pub fn process_part_2(input: &str) -> usize { let (_, assignments) = section_assignments(input).unwrap(); assignments .iter() .filter(|(a, b)| a.clone().into_iter().any(|n| b.contains(&n))) .count() } fn range_contains(haystack: &RangeInclusive, needle: &RangeInclusive) -> bool { haystack.contains(needle.start()) && haystack.contains(needle.end()) } fn section_assignments( input: &str, ) -> IResult<&str, Vec<(RangeInclusive, RangeInclusive)>> { use nom::character::complete::newline; use nom::multi::separated_list1; let (input, ranges) = separated_list1(newline, line)(input)?; Ok((input, ranges)) } fn line(input: &str) -> IResult<&str, (RangeInclusive, RangeInclusive)> { use nom::bytes::complete::tag; let (input, start) = sections(input)?; let (input, _) = tag(",")(input)?; let (input, end) = sections(input)?; Ok((input, (start, end))) } fn sections(input: &str) -> IResult<&str, RangeInclusive> { use nom::bytes::complete::tag; use nom::character::complete; let (input, start) = complete::u32(input)?; let (input, _) = tag("-")(input)?; let (input, end) = complete::u32(input)?; Ok((input, start..=end)) } #[cfg(test)] mod tests { use super::*; const INPUT: &str = "2-4,6-8 2-3,4-5 5-7,7-9 2-8,3-7 6-6,4-6 2-6,4-8"; #[test] fn day1() { assert_eq!(process_part_1(INPUT), 2); } #[test] fn day2() { assert_eq!(process_part_2(INPUT), 4); } }