//! Day 4: Camp Cleanup use std::ops::RangeInclusive; fn get_ranges(input: Vec) -> Vec<(RangeInclusive, RangeInclusive)> { // 31-31,32-40 input .into_iter() .map(|line| { let (r1, r2) = line.split_once(',').unwrap(); (parse_range(r1), parse_range(r2)) }) .collect() } fn parse_range(s: &str) -> RangeInclusive { let (a, b) = s.split_once('-').unwrap(); RangeInclusive::new(a.parse().unwrap(), b.parse().unwrap()) } pub fn part1(input: Vec) -> String { let ranges = get_ranges(input); ranges .iter() .filter(|(a, b)| { (b.start() >= a.start() && b.end() <= a.end()) || (a.start() >= b.start() && a.end() <= b.end()) }) .count() .to_string() } pub fn part2(input: Vec) -> String { let ranges = get_ranges(input); ranges .iter() .filter(|(a, b)| { a.contains(b.start()) || a.contains(b.end()) || b.contains(a.start()) || b.contains(a.end()) }) .count() .to_string() } #[cfg(test)] mod tests { use super::*; #[test] fn t_example() { let input = vec![ "2-4,6-8".to_owned(), "2-3,4-5".to_owned(), "5-7,7-9".to_owned(), "2-8,3-7".to_owned(), "6-6,4-6".to_owned(), "2-6,4-8".to_owned(), ]; assert_eq!(part1(input.clone()), "2"); assert_eq!(part2(input), "4"); } #[test] fn t_part1() { assert_eq!(part1(crate::read_input(4)), "556"); } #[test] fn t_part2() { assert_eq!(part2(crate::read_input(4)), "876"); } }