use std::collections::{HashMap, HashSet}; use color_eyre::Result; pub type CharSet = HashSet; #[derive(Debug)] pub struct Display(pub isize, pub CharSet); impl Display { pub fn parse(s: &str) -> Self { Self(s.len() as isize, CharSet::from_iter(s.chars())) } pub fn figure_out_from_others( others: Vec, ) -> Result> { let mut displays = HashMap::::new(); // Loop over all displays infinitely and stop when we've figured out all 10. for display in others.iter().cycle() { if displays.len() == 10 { break; } let length = display.0; let charset = display.1.clone(); // First check for the known unique segment lengths and insert them. if let Some(key) = match length { 2 => Some(1), 4 => Some(4), 3 => Some(7), 7 => Some(8), _ => None, } { displays.insert(key, charset); continue; } // Without the 1 and 4 segments we can't do anything else so grab those // or continue the loop. let (one, four) = match (displays.get(&1), displays.get(&4)) { (Some(one), Some(four)) => (one, four), _ => continue, }; // Create the subset we'll use to figure out 0 and 5 using the difference // between 4 and 1. let five_zero_subset = CharSet::from_iter(four.difference(one).copied()); // The segments for 2, 3 and 5 all have a length of 5. if length == 5 { // Only 3 has 1 as its subset. if one.is_subset(&charset) { displays.insert(3, charset); continue; } // Then only 5 will have the subset created earlier. if five_zero_subset.is_subset(&charset) { displays.insert(5, charset); continue; } // Then to figure out 2 we need to know both 3 and 5 so continue if we // haven't gotten them yet. let (three, five) = match (displays.get(&3), displays.get(&5)) { (Some(three), Some(five)) => (three, five), _ => continue, }; // Then 2 will simply be the remaining set of length 5 as long as it // doesn't equal 3 or 5. if ![three, five].contains(&&charset) { displays.insert(2, charset); continue; } } // The segments for 0, 6 and 9 all have length 6. if length == 6 { // Only 6 *does not* have the subset for 1. if !one.is_subset(&charset) { displays.insert(6, charset); continue; } // Then 0 *does not* have this subset from earlier. if !five_zero_subset.is_subset(&charset) { displays.insert(0, charset); continue; } let (zero, six) = match (displays.get(&0), displays.get(&6)) { (Some(zero), Some(six)) => (zero, six), _ => continue, }; // And again to figure out the remaining segment we use the other 2 // we know now. if ![zero, six].contains(&&charset) { displays.insert(9, charset); continue; } } } Ok(displays) } }