use std::collections::HashMap; use std::collections::HashSet; use std::io::stdin; use std::io::BufRead; const SEGMENTS: [char; 7] = ['a', 'b', 'c', 'd', 'e', 'f', 'g']; fn main() { println!("Hello, world!"); let arg = std::env::args().nth(1).unwrap_or("part2".to_string()); match arg.as_str() { "part1" => part1(), _ => part2(), }; } fn part1() { println!("Part1"); let mut lines = Vec::new(); let mut cur_line = String::new(); for line in stdin().lock().lines() { let line = line.unwrap().replace("_", ""); cur_line += &line; let last_char = line.chars().rev().nth(0).unwrap(); let is_wrapping = last_char == '|'; if !is_wrapping { lines.push(cur_line); cur_line = String::new() } else { cur_line.push(' '); } } dbg!(&lines); let mut count = 0; let interesting_lengths = HashSet::from([2, 3, 4, 7]); for line in lines { let second_part = line.split('|').nth(1).unwrap(); let count_interesting = second_part .split_whitespace() .filter(|s| interesting_lengths.contains(&s.len())) .count(); count += count_interesting; dbg!(second_part); dbg!(count_interesting); } dbg!(count); } fn part2() { println!("Part2"); let mut lines = Vec::new(); let mut cur_line = String::new(); for line in stdin().lock().lines() { let line = line.unwrap().replace("_", ""); cur_line += &line; let last_char = line.chars().rev().nth(0).unwrap(); let is_wrapping = last_char == '|'; if !is_wrapping { lines.push(cur_line); cur_line = String::new() } else { cur_line.push(' '); } } dbg!(&lines); let sum: i32 = lines.iter().map(|l| identify_numbers(l)).sum(); dbg!(sum); } fn identify_numbers(line: &str) -> i32 { let mut number_map = HashMap::new(); number_map.insert("abcefg".to_string(), 0); number_map.insert("cf".to_string(), 1); number_map.insert("acdeg".to_string(), 2); number_map.insert("acdfg".to_string(), 3); number_map.insert("bcdf".to_string(), 4); number_map.insert("abdfg".to_string(), 5); number_map.insert("abdefg".to_string(), 6); number_map.insert("acf".to_string(), 7); number_map.insert("abcdefg".to_string(), 8); number_map.insert("abcdfg".to_string(), 9); let mut possibilities = HashMap::new(); for segment in SEGMENTS { possibilities.insert(segment, HashSet::from(SEGMENTS)); } let words: Vec = line .split(&[' ', '|'][..]) .filter(|s| !s.is_empty()) .map(|s| s.to_string()) .collect(); let mut word_cycle = words.iter().cycle(); let mut last_hint = 0; let mut unclear: usize = possibilities.values().map(|set| set.len()).sum(); while unclear > SEGMENTS.len() { let word = &word_cycle.next().unwrap(); dbg!(word); if word.len() == 2 { let should_be = HashSet::from(['c', 'f']); let should_not_be = &HashSet::from(SEGMENTS) - &should_be; let word_chars: HashSet = word.chars().collect(); let word_inverse = &HashSet::from(SEGMENTS) - &word_chars; for a in word_chars { for b in &should_not_be { possibilities.get_mut(&a).unwrap().remove(&b); } } for a in word_inverse { for b in &should_be { possibilities.get_mut(&a).unwrap().remove(&b); } } } if word.len() == 3 { let should_be = HashSet::from(['a', 'c', 'f']); let should_not_be = &HashSet::from(SEGMENTS) - &should_be; let word_chars: HashSet = word.chars().collect(); let word_inverse = &HashSet::from(SEGMENTS) - &word_chars; for a in word_chars { for b in &should_not_be { possibilities.get_mut(&a).unwrap().remove(&b); } } for a in word_inverse { for b in &should_be { possibilities.get_mut(&a).unwrap().remove(&b); } } } if word.len() == 4 { let should_be = HashSet::from(['b', 'c', 'd', 'f']); let should_not_be = &HashSet::from(SEGMENTS) - &should_be; let word_chars: HashSet = word.chars().collect(); let word_inverse = &HashSet::from(SEGMENTS) - &word_chars; for a in word_chars { for b in &should_not_be { possibilities.get_mut(&a).unwrap().remove(&b); } } for a in word_inverse { for b in &should_be { possibilities.get_mut(&a).unwrap().remove(&b); } } } if word.len() == 5 { let should_be = HashSet::from(['b', 'c', 'e', 'f']); let should_not_be = &HashSet::from(SEGMENTS) - &should_be; let word_chars: HashSet = word.chars().collect(); let word_inverse = &HashSet::from(SEGMENTS) - &word_chars; for a in word_inverse { for b in &should_not_be { possibilities.get_mut(&a).unwrap().remove(&b); } } } if word.len() == 6 { let should_be = HashSet::from(['c', 'd', 'e']); let should_not_be = &HashSet::from(SEGMENTS) - &should_be; let word_chars: HashSet = word.chars().collect(); let word_inverse = &HashSet::from(SEGMENTS) - &word_chars; for a in word_inverse { for b in &should_not_be { possibilities.get_mut(&a).unwrap().remove(&b); } } } last_hint += 1; let new_unclear = possibilities.values().map(|set| set.len()).sum(); if new_unclear < unclear { last_hint = 0 } let clear: HashSet = possibilities .values() .filter(|set| set.len() == 1) .fold(HashSet::::new(), |acc, ele| { acc.union(ele).copied().collect() }); for val in possibilities.values_mut() { if val.len() > 1 { for c in &clear { val.remove(&c); } } } unclear = new_unclear; println!("{:?}", possibilities); if last_hint > words.len() { panic!("Loop detected. Cannot deduce segments"); } } println!("{:?}", possibilities); let signal_map: HashMap = possibilities .iter() .map(|(key, set)| (*key, *set.iter().next().unwrap())) .collect(); println!("signal map: {:?}", signal_map); let mut num = 0; let mut multiplier = 1; for word in words.iter().rev().take(4) { let mut signal: Vec = word.chars().map(|c| *signal_map.get(&c).unwrap()).collect(); signal.sort(); let signal: String = signal.iter().collect(); dbg!(&signal); let digit = number_map.get(&signal).unwrap(); num += digit * multiplier; multiplier *= 10; dbg!(digit); } dbg!(num); return num; }