pub fn part1<'a, I, S>(lines: I) -> u32 where I: IntoIterator<Item = &'a S>, S: AsRef<str> + 'a, { lines .into_iter() .filter_map(|line| { let mut expected = Vec::new(); for c in line.as_ref().chars() { if c == '(' { expected.push(')') } else if c == '[' { expected.push(']') } else if c == '{' { expected.push('}') } else if c == '<' { expected.push('>') } else if Some(c) == expected.pop() { } else if c == ')' { return Some(3); } else if c == ']' { return Some(57); } else if c == '}' { return Some(1197); } else if c == '>' { return Some(25137); } else { return None; } } None }) .sum() } pub fn part2<'a, I, S>(lines: I) -> Option<u64> where I: IntoIterator<Item = &'a S>, S: AsRef<str> + 'a, { let mut scores = Vec::new(); 'outer: for line in lines { let mut expected = Vec::new(); for c in line.as_ref().chars() { if c == '(' { expected.push(')') } else if c == '[' { expected.push(']') } else if c == '{' { expected.push('}') } else if c == '<' { expected.push('>') } else if Some(c) == expected.pop() { } else { continue 'outer; } } scores.push( expected .into_iter() .rev() .filter_map(|c| match c { ')' => Some(1), ']' => Some(2), '}' => Some(3), '>' => Some(4), _ => None, }) .fold(0, |acc, x| 5 * acc + x), ); } scores.sort_unstable(); scores.get(scores.len() / 2).cloned() } #[cfg(test)] mod tests { use super::*; use pretty_assertions::assert_eq; static EXAMPLE: &[&str] = &[ "[({(<(())[]>[[{[]{<()<>>", "[(()[<>])]({[<{<<[]>>(", "{([(<{}[<>[]}>{[]{[(<()>", "(((({<>}<{<{<>}{[]{[]{}", "[[<[([]))<([[{}[[()]]]", "[{[{({}]{}}([{[{{{}}([]", "{<[[]]>}<{[{[{[]{()[[[]", "[<(<(<(<{}))><([]([]()", "<{([([[(<>()){}]>(<<{{", "<{([{{}}[<[[[<>{}]]]>[]]", ]; #[test] fn part1_examples() { assert_eq!(26397, part1(EXAMPLE)); } #[test] fn part2_examples() { assert_eq!(Some(288957), part2(EXAMPLE)); } }