use crate::puzzle::Puzzle; use nom::{ Parser, character::complete::{char, digit1, newline}, combinator::{eof, map_res}, error::Error, multi::separated_list1, sequence::{separated_pair, terminated}, }; pub const PUZZLE: Puzzle, usize, 2> = Puzzle { number: 2, parser: |input| { terminated( terminated( separated_list1( char(','), separated_pair(parse_int(), char('-'), parse_int()), ), newline, ), eof, ) .parse(input) .unwrap() .1 }, parts: [ |input| { input .into_iter() .flat_map(|(l, u)| { (*l..(u + 1)).flat_map(|n| if is_repetition_2(n) { Some(n) } else { None }) }) .sum() }, |input| { input .into_iter() .flat_map(|(l, u)| { (*l..(u + 1)).flat_map(|n| if is_repetition_n(n) { Some(n) } else { None }) }) .sum() }, ], }; fn is_repetition_2(n: usize) -> bool { let n = n.to_string(); let l = n.len(); let d = l / 2; let r = l % 2; if r == 0 { equal_chunks(&n, d) } else { false } } fn is_repetition_n(n: usize) -> bool { let n = n.to_string(); let l = n.len(); let d = l / 2; (1..(d + 1)).any(|i| equal_chunks(&n, i)) } fn equal_chunks(n: &String, i: usize) -> bool { let chars = n.chars().collect::>(); let mut chunks = (chars[..]).chunks(i); match chunks.next() { None => true, Some(x) => chunks.all(|y| y == x), } } fn parse_int<'a>() -> impl Parser<&'a str, Output = usize, Error = Error<&'a str>> { map_res(digit1, |s: &str| s.parse::()) }