diff --git a/src/day5.rs b/src/day5.rs new file mode 100644 index 0000000..303dc81 --- /dev/null +++ b/src/day5.rs @@ -0,0 +1,143 @@ +use std::cmp; + +#[derive(Copy, Clone, Debug)] +struct UintInclusiveRange { + start: u64, + end: u64, +} + +impl UintInclusiveRange { + fn new(start: u64, end: u64) -> Self { + UintInclusiveRange { + start: start, + end: end, + } + } + + fn in_range(&self, value: u64) -> bool { + value >= self.start && value <= self.end + } + + fn overlaps(&self, other: &UintInclusiveRange) -> bool { + (self.start >= other.start && self.start <= other.end) + || (self.end >= other.start && self.end <= other.end) + || (self.start <= other.start && self.end >= other.end) + || (self.start >= other.start && self.end <= other.end) + } + + fn join(&self, other: &UintInclusiveRange) -> UintInclusiveRange { + println!( + "Joining {:?} and {:?} into {:?}", + self, + other, + UintInclusiveRange::new( + cmp::min(self.start, other.start), + cmp::max(self.end, other.end), + ) + ); + assert!(self.overlaps(&other)); + UintInclusiveRange::new( + cmp::min(self.start, other.start), + cmp::max(self.end, other.end), + ) + } + + fn size(self) -> u64 { + self.end - self.start + 1 + } +} + +fn parse_input(input: &str) -> (Vec, Vec) { + ( + input + .split("\n") + .take_while(|x| *x != "") + .map(|x| { + UintInclusiveRange::new( + x.split("-").nth(0).unwrap().parse().unwrap(), + x.split("-").nth(1).unwrap().parse().unwrap(), + ) + }) + .collect::>(), + input + .split("\n") + .skip_while(|x| *x != "") + .filter(|&x| !x.is_empty()) + .map(|x| x.parse::().unwrap()) + .collect(), + ) +} + +#[aoc(day5, part1)] +pub fn part1(input: &str) -> u64 { + let (fresh_ingredients, available_ingredients) = parse_input(input); + available_ingredients + .iter() + .filter(|x| fresh_ingredients.iter().any(|y| y.in_range(**x))) + .count() as u64 +} + +#[aoc(day5, part2)] +pub fn part2(input: &str) -> u64 { + let (mut fresh_ingredients, _) = parse_input(input); + + let mut joined_ingredients = >::new(); + + fresh_ingredients.sort_by(|x, y| x.start.cmp(&y.start)); + let mut init = UintInclusiveRange::new(0, 0); + + for ingredient in &fresh_ingredients { + if ingredient.start <= init.end { + init = UintInclusiveRange::new(init.start, init.end.max(ingredient.end)); + } else { + if init.start != 0 && init.end != 0 { + joined_ingredients.push(init); + } + init = UintInclusiveRange::new(ingredient.start, ingredient.end); + } + } + + joined_ingredients.push(init); + + joined_ingredients.iter().map(|x| x.size()).sum() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_part1() { + let test_input = String::from( + "3-5 +10-14 +16-20 +12-18 + +1 +5 +8 +11 +17 +32", + ); + assert_eq!(part1(&test_input), 3) + } + #[test] + fn test_part2() { + let test_input = String::from( + "3-5 +10-14 +16-20 +12-18 + +1 +5 +8 +11 +17 +32", + ); + assert_eq!(part2(&test_input), 14) + } +} diff --git a/src/lib.rs b/src/lib.rs index 3e01eb1..c7ba38e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,7 @@ extern crate aoc_runner_derive; // pub mod day1; // pub mod day2; // pub mod day3; -pub mod day4; +// pub mod day4; +pub mod day5; aoc_lib! { year = 2025 }