Advent of Rust // Day 4
The plural of regex is regrets, some people say, but I like ‘em. Not for everything and all the time but they come in handy for some tasks. Like this, for example:
fn line_to_sections_pair(line: &str) -> (Sections, Sections) {
let re = Regex::new(r"^(\d+)-(\d+),(\d+)-(\d+)$").unwrap();
let captures = re.captures(line).unwrap();
return (
Sections::new(captures[1].parse().unwrap(), captures[2].parse().unwrap()),
Sections::new(captures[3].parse().unwrap(), captures[4].parse().unwrap())
);
}
Sections
in the code above, in case you’re wondering, is just a type alias for RangeInclusive<u32>
. Both parts of the puzzle had essentially the same task: to count the number of pairs that match a certain criterion.
fn number_of_matching_pairs(input: Vec<&str>, filter: fn(a: &Sections, b: &Sections) -> bool) -> u32 {
return input.iter()
.map(|l| line_to_sections_pair(l))
.filter(|(a, b)| filter(a, b))
.count() as u32;
}
For part one, either of the two sections must be contained in the other:
fn is_either_contained(a: &Sections, b: &Sections) -> bool {
return (b.contains(a.start()) && b.contains(a.end())) ||
(a.contains(b.start()) && a.contains(b.end()));
}
For part two, both sections must have an overlap:
fn is_overlapping(a: &Sections, b: &Sections) -> bool {
return b.contains(a.start()) || b.contains(a.end()) ||
a.contains(b.start()) || a.contains(b.end());
}
Plugged together:
fn part_one(input: Vec<&str>) -> u32 {
return number_of_matching_pairs(input, is_either_contained);
}
fn part_two(input: Vec<&str>) -> u32 {
return number_of_matching_pairs(input, is_overlapping);
}
fn main() {
let input = fs::read_to_string("input/day04.txt").unwrap();
println!("Part One: {}", part_one(input.lines().collect()));
println!("Part Two: {}", part_two(input.lines().collect()));
}
I went deeper down the rabbit hole of testing in Rust and was looking for ways to do parameterized tests. The first thing I discovered was rstest and I gave it a try. It worked like a charm for what I wanted to do.
#[rstest]
#[case(1..=2, 3..=4, false)]
#[case(5..=6, 3..=4, false)]
#[case(1..=3, 3..=4, true)]
#[case(1..=5, 3..=4, true)]
fn is_overlapping_test(#[case] a: Sections, #[case] b: Sections, #[case] expected: bool) {
assert_eq!(
expected,
is_overlapping(&a, &b),
"{a:?} {} overlap with {b:?}", if expected { "should" } else { "should not" }
);
}
The full source and solutions for the others puzzles of Advent of Code can be found in my GitHub repository.
Comments
You can leave a comment by replying to this post on Mastodon.