year2025/
day05.rs

1use std::cmp::Ordering;
2use utils::prelude::*;
3
4/// Merging integer ranges.
5#[derive(Clone, Debug)]
6pub struct Day05 {
7    ranges: Vec<[u64; 2]>,
8    ids: Vec<u64>,
9}
10
11impl Day05 {
12    pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
13        let (ranges, ids) = parser::u64()
14            .repeat_n(b'-')
15            .repeat(parser::eol(), 1)
16            .with_eol()
17            .with_eol()
18            .then(parser::u64().repeat(parser::eol(), 1))
19            .parse_complete(input)?;
20
21        Ok(Self {
22            ranges: Self::merge_ranges(ranges),
23            ids,
24        })
25    }
26
27    #[must_use]
28    pub fn part1(&self) -> usize {
29        self.ids
30            .iter()
31            .filter(|&&id| {
32                self.ranges
33                    .binary_search_by(|&[s, e]| {
34                        if e < id {
35                            Ordering::Less
36                        } else if s > id {
37                            Ordering::Greater
38                        } else {
39                            Ordering::Equal
40                        }
41                    })
42                    .is_ok()
43            })
44            .count()
45    }
46
47    #[must_use]
48    pub fn part2(&self) -> u64 {
49        self.ranges.iter().map(|[s, e]| e - s + 1).sum()
50    }
51
52    fn merge_ranges(mut ranges: Vec<[u64; 2]>) -> Vec<[u64; 2]> {
53        if ranges.is_empty() {
54            return ranges;
55        }
56
57        ranges.sort_unstable_by_key(|&[s, _]| s);
58
59        let [mut start, mut end] = ranges[0];
60        ranges = ranges
61            .into_iter()
62            .flat_map(|[s, e]| {
63                if s > end.saturating_add(1) {
64                    let result = [start, end];
65                    [start, end] = [s, e];
66                    Some(result)
67                } else {
68                    end = end.max(e);
69                    None
70                }
71            })
72            .collect();
73        ranges.push([start, end]);
74
75        ranges
76    }
77}
78
79examples!(Day05 -> (usize, u64) [
80    {input: "3-5\n10-14\n16-20\n12-18\n\n1\n5\n8\n11\n17\n32", part1: 3, part2: 14},
81]);