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) }