diff --git a/2022/day4/rust/src/main.rs b/2022/day4/rust/src/main.rs index 5b5c611..5ae7f37 100644 --- a/2022/day4/rust/src/main.rs +++ b/2022/day4/rust/src/main.rs @@ -1,4 +1,42 @@ -use std::io::{stdin, Read}; +#![warn(clippy::pedantic)] +#![feature(is_some_and)] + +use std::{ + io::{stdin, Read}, + ops::{BitAnd, RangeInclusive}, +}; + +/// A range of sections. Always contains at least one element. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +struct SectionRange { + start: u64, + end: u64, +} + +impl TryFrom> for SectionRange { + type Error = (); + + fn try_from(range: RangeInclusive) -> Result { + let start = *range.start(); + let end = *range.end(); + if start <= end { + Ok(Self { start, end }) + } else { + Err(()) + } + } +} + +impl BitAnd for SectionRange { + type Output = Option; + + fn bitand(self, other: Self) -> Self::Output { + let start = self.start.max(other.start); + let end = self.end.min(other.end); + + Self::try_from(start..=end).ok() + } +} fn main() { let mut data = String::new(); @@ -10,11 +48,10 @@ fn main() { let make_range = |s: &str| { let (start, end) = s.split_once('-').unwrap(); - let start: u64 = start.parse().unwrap(); + let start = start.parse().unwrap(); let end = end.parse().unwrap(); - assert!(start <= end); - start..=end + SectionRange::try_from(start..=end).unwrap() }; let (left, right) = line.split_once(',').unwrap(); @@ -29,17 +66,11 @@ fn main() { "{}", pairs .iter() - .filter(|(l, r)| l.start() == r.start() - || l.end() == r.end() - || l.start().cmp(r.start()) != l.end().cmp(r.end())) + .filter(|&&(l, r)| { + (l & r).is_some_and(|intersection| intersection == l || intersection == r) + }) .count() ); - println!( - "{}", - pairs - .iter() - .filter(|(l, r)| l.end() >= r.start() && r.end() >= l.start()) - .count() - ); + println!("{}", pairs.iter().filter_map(|&(l, r)| l & r).count()); }