diff --git a/src/bin/02.rs b/src/bin/02.rs new file mode 100644 index 0000000..53742cb --- /dev/null +++ b/src/bin/02.rs @@ -0,0 +1,62 @@ +use aoc::*; + +const INPUT: &str = include_str!("../../input/02"); + +fn main() { + println!("Part 1: {}", part1(INPUT)); + println!("Part 2: {}", part2(INPUT)); +} + +#[test] +fn example() { + assert_example!(part1, "02-test", 1227775554); + assert_example!(part2, "02-test", 4174379265); +} + +fn part1(input: &str) -> usize { + parse_input(input) + .map(|r| r.invalid_id_sum(is_doubled)) + .sum() +} + +fn part2(input: &str) -> usize { + parse_input(input) + .map(|r| r.invalid_id_sum(is_repeated)) + .sum() +} + +fn is_doubled(id: usize) -> bool { + let id = id.to_string(); + let (hi, lo) = id.split_at(id.len() / 2); + hi == lo +} + +fn is_repeated(id: usize) -> bool { + let id = id.to_string(); + + (1..id.len()) + .map(|prefix_len| &id[0..prefix_len]) + .any(|prefix| id.trim_start_matches(prefix).is_empty()) +} + +struct Range { + from: usize, + to: usize, +} + +impl Range { + fn parse(s: &str) -> Self { + let (from, to) = s.split_once('-').unwrap(); + let from = from.trim().parse().unwrap(); + let to = to.trim().parse().unwrap(); + Self { from, to } + } + + fn invalid_id_sum(self, is_invalid: fn(usize) -> bool) -> usize { + (self.from..=self.to).filter(|&n| is_invalid(n)).sum() + } +} + +fn parse_input(input: &str) -> impl Iterator + use<'_> { + input.split(',').map(Range::parse) +}