1use std::cmp::Ordering;
2use utils::prelude::*;
3
4#[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]);