fn contains(a: &str, b: &str) -> bool { b.chars().all(|c| a.contains(c)) } fn find_bd(one: &str, four: &str) -> String { four.chars() .filter(|c| !one.contains(*c)) .collect::() } fn hash(s: &str) -> u32 { s.chars() .map(|c| match c { 'a' => 2, 'b' => 3, 'c' => 5, 'd' => 7, 'e' => 11, 'f' => 13, 'g' => 17, _ => panic!(), }) .product() } fn decode_digit<'a, I>(patterns: &[&str], digit_positions: I, output: &str) -> u32 where I: Iterator, { *digit_positions .zip(patterns) .find(|(_i, p)| hash(p) == hash(output)) .unwrap() .0 } fn decode(patterns: Vec<&str>, outputs: Vec<&str>) -> u32 { let one = patterns.iter().find(|p| p.len() == 2).unwrap(); let four = patterns.iter().find(|p| p.len() == 4).unwrap(); let bd = find_bd(one, four); let digit_positions = patterns .iter() .map(|p| match p.len() { 2 => 1, 4 => 4, 3 => 7, 7 => 8, 5 if !contains(p, one) && !contains(p, &bd) => 2, 5 if contains(p, one) => 3, 5 if contains(p, &bd) => 5, 6 if !contains(p, one) => 6, 6 if contains(p, four) => 9, 6 if contains(p, one) && !contains(p, four) => 0, _ => panic!(), }) .collect::>(); let mut iter = outputs.into_iter(); decode_digit(&patterns, digit_positions.iter(), iter.next().unwrap()) * 1000 + decode_digit(&patterns, digit_positions.iter(), iter.next().unwrap()) * 100 + decode_digit(&patterns, digit_positions.iter(), iter.next().unwrap()) * 10 + decode_digit(&patterns, digit_positions.iter(), iter.next().unwrap()) } fn main() { const INPUT: &str = include_str!("../inputs/day8.txt"); let easy_digits = INPUT .lines() .map(|line| { line.split_ascii_whitespace() .rev() .take(4) .filter(|d| d.len() == 2 || d.len() == 3 || d.len() == 4 || d.len() == 7) .count() }) .sum::(); println!("solution {}", easy_digits); let digits = INPUT .lines() .map(|line| { let (unique_patterns, outputs) = line .split_once(" | ") .map(|(s, t)| { ( s.split_ascii_whitespace().collect(), t.split_ascii_whitespace().collect(), ) }) .unwrap(); decode(unique_patterns, outputs) }) .sum::(); println!("solution {}", digits); } #[test] fn test_decode() { let unique_patterns = vec![ "be", "cfbegad", "cbdgef", "fgaecd", "cgeb", "fdcge", "agebfd", "fecdb", "fabcd", "edb", ]; let outputs = vec!["fdgacbe", "cefdb", "cefbgd", "gcbe"]; assert_eq!(decode(unique_patterns, outputs), 8394); } #[test] fn test_hash() { assert_eq!(hash("cefbgd"), 3 * 5 * 7 * 11 * 13 * 17); }