advent_of_code/year2022/
day04.rs1use crate::input::Input;
2
3fn parse_intervals(line: &str) -> Option<((u8, u8), (u8, u8))> {
4 fn parse_range(range: &str) -> Option<(u8, u8)> {
5 let (s1, s2) = range.split_once('-')?;
6 Some((s1.parse().ok()?, s2.parse().ok()?))
7 }
8
9 let (a, b) = line.split_once(',')?;
10 Some((parse_range(a)?, parse_range(b)?))
11}
12
13const fn contains(a: (u8, u8), b: (u8, u8)) -> bool {
14 b.0 >= a.0 && b.1 <= a.1 || a.0 >= b.0 && a.1 <= b.1
15}
16
17const fn overlaps(a: (u8, u8), b: (u8, u8)) -> bool {
18 b.0 <= a.1 && b.1 >= a.0
19}
20
21pub fn solve(input: &Input) -> Result<usize, String> {
22 let condition: fn((u8, u8), (u8, u8)) -> bool = input.part_values(contains, overlaps);
23
24 input
25 .text
26 .lines()
27 .enumerate()
28 .map(|(line_idx, line)| {
29 let intervals = parse_intervals(line).ok_or_else(|| {
30 format!("Line {line_idx}: Invalid input - expected 'u8-u8,u8-u8'")
31 })?;
32 Ok(usize::from(condition(intervals.0, intervals.1)))
33 })
34 .sum()
35}
36
37#[test]
38pub fn tests() {
39 use crate::input::{
40 test_part_one_error, test_part_one_no_allocations, test_part_two_no_allocations,
41 };
42
43 let test_input = "2-4,6-8
442-3,4-5
455-7,7-9
462-8,3-7
476-6,4-6
482-6,4-8";
49 test_part_one_no_allocations!(test_input => 2);
50 test_part_two_no_allocations!(test_input => 4);
51
52 let real_input = include_str!("day04_input.txt");
53 test_part_one_no_allocations!(real_input => 569);
54 test_part_two_no_allocations!(real_input => 936);
55
56 for input in ["1-2,3-4\nfoo", "1-2,3-4\n300-400,1-2", "1-2,3-4\n-1-2,3-4"] {
57 test_part_one_error!(input => "Line 1: Invalid input - expected 'u8-u8,u8-u8'");
58 }
59}