use std::collections::HashSet; pub struct Input { pub unique_combinations: Vec, pub output_values: Vec, } #[derive(Debug, PartialEq, Clone)] pub struct Ssd { pub a: HashSet, pub b: HashSet, pub c: HashSet, pub d: HashSet, pub e: HashSet, pub f: HashSet, pub g: HashSet, } impl Default for Ssd { fn default() -> Self { let possible_pins: HashSet = "abcdefg".chars().collect(); Self { a: possible_pins.clone(), b: possible_pins.clone(), c: possible_pins.clone(), d: possible_pins.clone(), e: possible_pins.clone(), f: possible_pins.clone(), g: possible_pins, } } } impl Ssd { pub fn try_decode(&mut self, number: &str) -> Option { let number: HashSet = number.chars().collect(); match number.len() { 2 => { self.a.retain(|c| !number.contains(c)); self.b.retain(|c| !number.contains(c)); self.c.retain(|c| number.contains(c)); self.d.retain(|c| !number.contains(c)); self.e.retain(|c| !number.contains(c)); self.f.retain(|c| number.contains(c)); self.g.retain(|c| !number.contains(c)); Some('1') } 3 => { self.a.retain(|c| number.contains(c)); self.b.retain(|c| !number.contains(c)); self.c.retain(|c| number.contains(c)); self.d.retain(|c| !number.contains(c)); self.e.retain(|c| !number.contains(c)); self.f.retain(|c| number.contains(c)); self.g.retain(|c| !number.contains(c)); Some('7') } 4 => { self.a.retain(|c| !number.contains(c)); self.b.retain(|c| number.contains(c)); self.c.retain(|c| number.contains(c)); self.d.retain(|c| number.contains(c)); self.e.retain(|c| !number.contains(c)); self.f.retain(|c| number.contains(c)); self.g.retain(|c| !number.contains(c)); Some('4') } 5 => { let full: HashSet = "abcdefg".chars().collect(); let missing = full.difference(&number).copied().collect::>(); let four = self.get_number_set(4); let one = self.get_number_set(1); let missing_six = full .difference(&self.get_number_set(6)) .copied() .collect::>(); let missing_nince = full .difference(&self.get_number_set(9)) .copied() .collect::>(); let missing_five = missing_six .union(&missing_nince) .copied() .collect::>(); if missing.is_disjoint(&one) { self.a.retain(|c| number.contains(c)); self.b.retain(|c| !number.contains(c)); self.c.retain(|c| number.contains(c)); self.d.retain(|c| number.contains(c)); self.e.retain(|c| !number.contains(c)); self.f.retain(|c| number.contains(c)); self.g.retain(|c| number.contains(c)); Some('3') } else if missing.is_subset(&four) { self.a.retain(|c| number.contains(c)); self.b.retain(|c| !number.contains(c)); self.c.retain(|c| number.contains(c)); self.d.retain(|c| number.contains(c)); self.e.retain(|c| number.contains(c)); self.f.retain(|c| !number.contains(c)); self.g.retain(|c| number.contains(c)); Some('2') } else if missing == missing_five { self.a.retain(|c| number.contains(c)); self.b.retain(|c| number.contains(c)); self.c.retain(|c| !number.contains(c)); self.d.retain(|c| number.contains(c)); self.e.retain(|c| !number.contains(c)); self.f.retain(|c| number.contains(c)); self.g.retain(|c| number.contains(c)); Some('5') } else { None } } 6 => { let full: HashSet = "abcdefg".chars().collect(); let missing = full.difference(&number).copied().collect::>(); let four = self.get_number_set(4); let one = self.get_number_set(1); if missing.is_disjoint(&four) { self.a.retain(|c| number.contains(c)); self.b.retain(|c| number.contains(c)); self.c.retain(|c| number.contains(c)); self.d.retain(|c| number.contains(c)); self.e.retain(|c| !number.contains(c)); self.f.retain(|c| number.contains(c)); self.g.retain(|c| number.contains(c)); Some('9') } else if missing.is_disjoint(&one) { self.a.retain(|c| number.contains(c)); self.b.retain(|c| number.contains(c)); self.c.retain(|c| number.contains(c)); self.d.retain(|c| !number.contains(c)); self.e.retain(|c| number.contains(c)); self.f.retain(|c| number.contains(c)); self.g.retain(|c| number.contains(c)); Some('0') } else { self.a.retain(|c| number.contains(c)); self.b.retain(|c| number.contains(c)); self.c.retain(|c| !number.contains(c)); self.d.retain(|c| number.contains(c)); self.e.retain(|c| number.contains(c)); self.f.retain(|c| number.contains(c)); self.g.retain(|c| number.contains(c)); Some('6') } } 7 => Some('8'), _ => None, } } fn get_number_set(&self, num: usize) -> HashSet { Self::merge_sets(self.get_number_sets(num)) } fn get_number_sets(&self, num: usize) -> Vec> { match num { 1 => vec![&self.c, &self.f], 2 => vec![&self.a, &self.c, &self.d, &self.e, &self.g], 3 => vec![&self.a, &self.c, &self.d, &self.f, &self.g], 4 => vec![&self.b, &self.c, &self.d, &self.f], 5 => vec![&self.a, &self.b, &self.d, &self.f, &self.g], 6 => vec![&self.a, &self.b, &self.d, &self.e, &self.f, &self.g], 7 => vec![&self.a, &self.c, &self.f], 8 => vec![ &self.a, &self.b, &self.c, &self.d, &self.e, &self.f, &self.g, ], 9 => vec![&self.a, &self.b, &self.c, &self.d, &self.f, &self.g], 0 => vec![&self.a, &self.b, &self.c, &self.e, &self.f, &self.g], _ => panic!(), } .iter() .map(|set| set.iter().copied().collect()) .collect() } fn merge_sets(sets: Vec>) -> HashSet { sets.iter().flat_map(HashSet::iter).copied().collect() } } #[cfg(test)] mod test { use super::Ssd; #[test] fn try_decode_trivials() { let mut ssd = Ssd::default(); dbg!(&ssd); assert_eq!(ssd.try_decode("cf"), Some('1')); dbg!(&ssd); assert_eq!(ssd.try_decode("acf"), Some('7')); dbg!(&ssd); assert_eq!(ssd.try_decode("bcdf"), Some('4')); dbg!(&ssd); assert_eq!(ssd.try_decode("abcdefg"), Some('8')); } #[test] fn try_decode() { let mut ssd = Ssd::default(); dbg!(&ssd); assert_eq!(ssd.try_decode("gf"), Some('1')); dbg!(&ssd); assert_eq!(ssd.try_decode("fgd"), Some('7')); dbg!(&ssd); assert_eq!(ssd.try_decode("fgec"), Some('4')); dbg!(&ssd); assert_eq!(ssd.try_decode("bdegcaf"), Some('8')); dbg!(&ssd); assert_eq!(ssd.try_decode("aegbdf"), Some('0')); dbg!(&ssd); assert_eq!(ssd.try_decode("ecdfab"), Some('6')); dbg!(&ssd); assert_eq!(ssd.try_decode("gdcebf"), Some('9')); dbg!(&ssd); assert_eq!(ssd.try_decode("dbcfg"), Some('3')); dbg!(&ssd); assert_eq!(ssd.try_decode("dacgb"), Some('2')); dbg!(&ssd); assert_eq!(ssd.try_decode("fbedc"), Some('5')); } }