use { anyhow::{ anyhow, Context, Result, }, regex::Regex, std::{ env::args, fmt, fs::File, io::{ BufRead, BufReader, }, path::Path, }, }; struct SectionAssignment { start: usize, end: usize, } impl SectionAssignment { fn new(start: usize, end: usize) -> Self { Self { start, end, } } fn contains(&self, other: &SectionAssignment) -> bool { self.start <= other.start && self.end >= other.end } fn overlaps(&self, other: &SectionAssignment) -> bool { (self.start >= other.start && self.start <= other.end) || (self.end >= other.start && self.end <= other.end) || (other.start >= self.start && other.start <= self.end) || (other.end >= self.start && other.end <= self.end) } } impl fmt::Debug for SectionAssignment { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { (0..=9).map(|i| if i >= self.start && i <= self.end { write!(f, "{i}") } else { write!(f, ".") }).last(); write!(f, " {}-{}", self.start, self.end)?; Ok(()) } } type AssignmentPair = [SectionAssignment; 2]; fn read_input>(filename: T) -> Result> { let reader = BufReader::new(File::open(filename)?); let re = Regex::new(r"(?P[0-9]+)-(?P[0-9]+),(?P[0-9]+)-(?P[0-9]+)") .context("Regex compilation failed.")?; reader.lines().map( |v| { let s = v?; let caps = re.captures(&s).ok_or_else(|| anyhow!("Regex matching failed."))?; match (caps.name("s0"), caps.name("e0"), caps.name("s1"), caps.name("e1")) { ( Some(s0), Some(e0), Some(s1), Some(e1) ) => Ok([ SectionAssignment::new(s0.as_str().parse()?, e0.as_str().parse()?), SectionAssignment::new(s1.as_str().parse()?, e1.as_str().parse()?), ]), _ => Err(anyhow!("Parse error.")), } } ).collect() } fn part1(input: &[AssignmentPair]) -> Result { Ok(input.iter().filter(|pair| pair[0].contains(&pair[1]) || pair[1].contains(&pair[0])).count()) } fn part2(input: &[AssignmentPair]) -> Result { Ok(input.iter().filter(|pair| pair[0].overlaps(&pair[1])).count()) } fn main() -> Result<()> { let ( do_part_1, do_part_2 ) = aoc::do_parts(); let filename = args().nth(1).ok_or_else(|| anyhow!("Missing input filename"))?; let input = read_input(filename).context("Could not read input")?; if do_part_1 { let solution = part1(&input).context("No solution for part 1")?; println!("Part1, solution found to be: {}", solution); } if do_part_2 { let solution = part2(&input).context("No solution for part 2")?; println!("Part2, solution found to be: {}", solution); } Ok(()) }