use nom::{ bytes::complete::tag, character::complete::{line_ending, u32 as nom_u32}, combinator::map, multi::separated_list1, sequence::tuple, IResult, }; use std::{fs, iter::Iterator, ops::RangeInclusive}; fn main() -> Result<(), Box> { let input = fs::read_to_string("inputs/day_4.txt")?; let assignments = Assignments::parser(&input).unwrap().1; dbg!(assignments.count_containing_assignments()); dbg!(assignments.count_overlapping_assignments()); Ok(()) } #[derive(Debug, PartialEq, Eq, Clone)] struct Assignments(Vec); #[derive(Debug, PartialEq, Eq, Clone)] struct AssignmentPair { elf_1: Assignment, elf_2: Assignment, } #[derive(Debug, PartialEq, Eq, Clone)] struct Assignment(RangeInclusive); impl Assignments { fn parser(input: &str) -> IResult<&str, Assignments> { map( separated_list1(line_ending, AssignmentPair::parser), Assignments, )(input) } fn count_containing_assignments(&self) -> usize { self.0 .iter() .filter(|pair| pair.one_completely_overlaps_other()) .count() } fn count_overlapping_assignments(&self) -> usize { self.0 .iter() .filter(|pair| pair.one_overlaps_other()) .count() } } impl AssignmentPair { fn parser(input: &str) -> IResult<&str, AssignmentPair> { map( tuple((Assignment::parser, tag(","), Assignment::parser)), |(elf_1, _, elf_2)| AssignmentPair { elf_1, elf_2 }, )(input) } fn one_completely_overlaps_other(&self) -> bool { self.elf_1.contains(&self.elf_2) || self.elf_2.contains(&self.elf_1) } fn one_overlaps_other(&self) -> bool { self.elf_1.overlaps(&self.elf_2) } } impl Assignment { fn parser(input: &str) -> IResult<&str, Assignment> { map(tuple((nom_u32, tag("-"), nom_u32)), |(start, _, end)| { Assignment(RangeInclusive::new(start, end)) })(input) } fn contains(&self, other: &Assignment) -> bool { self.0.contains(other.0.start()) && self.0.contains(other.0.end()) } fn overlaps(&self, other: &Assignment) -> bool { self.0.contains(other.0.start()) || self.0.contains(other.0.end()) || other.0.contains(self.0.start()) || other.0.contains(self.0.end()) } }