diff --git a/src/day4.rs b/src/day4.rs new file mode 100644 index 0000000..9329b27 --- /dev/null +++ b/src/day4.rs @@ -0,0 +1,67 @@ +use std::{io::BufRead, ops::RangeInclusive}; + +use aoc_runner_derive::{aoc, aoc_generator}; + +struct Pair([RangeInclusive; 2]); + +impl From<&str> for Pair { + fn from(value: &str) -> Self { + let ranges = value.split_once(',').unwrap(); + Pair([parse_range(ranges.0), parse_range(ranges.1)]) + } +} + +impl Pair { + fn fully_contained(&self) -> bool { + (self.0[0].start() <= self.0[1].start() && self.0[0].end() >= self.0[1].end()) + || (self.0[1].start() <= self.0[0].start() && self.0[1].end() >= self.0[0].end()) + } + fn overlaps(&self) -> bool { + self.0[0].contains(self.0[1].start()) + || self.0[0].contains(self.0[1].end()) + || self.0[1].contains(self.0[0].start()) + || self.0[1].contains(self.0[0].end()) + } +} + +fn parse_range(s: &str) -> RangeInclusive { + let (lower, upper) = s.split_once('-').unwrap(); + RangeInclusive::new(lower.parse().unwrap(), upper.parse().unwrap()) +} + +#[aoc_generator(day4)] +fn parse(input: &str) -> Vec { + input.lines().map(|l| l.into()).collect() +} + +#[aoc(day4, part1)] +fn part1(input: &Vec) -> u64 { + input.iter().filter(|p| p.fully_contained()).count() as u64 +} + +#[aoc(day4, part2)] +fn part2(input: &Vec) -> u64 { + input.iter().filter(|p| p.overlaps()).count() as u64 +} + +#[cfg(test)] +mod tests { + use super::*; + + const EXAMPLE: &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 part1_example() { + assert_eq!(part1(&parse(EXAMPLE)), 2); + } + + #[test] + fn part2_example() { + assert_eq!(part2(&parse(EXAMPLE)), 4); + } +} diff --git a/src/lib.rs b/src/lib.rs index 72cdbc0..53776f7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +mod day4; mod day1; mod day2; mod day3;