diff --git a/src/letterset.rs b/src/letterset.rs index 3b51fe5..bf9838c 100644 --- a/src/letterset.rs +++ b/src/letterset.rs @@ -1,6 +1,6 @@ use std::{fmt, ops::Deref}; -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default, Debug, Hash)] pub struct LetterSet(u32); /// Immutable set of English letters @@ -60,6 +60,10 @@ impl LetterSet { self.0.count_ones() as u8 } + pub const fn is_empty(self) -> bool { + self.0 == 0 + } + const fn letter_index(letter: u8) -> Option { if letter.is_ascii_alphabetic() { let lower = letter.to_ascii_lowercase(); @@ -98,6 +102,15 @@ where } } +impl From for LetterSet +where + T: AsRef<[u8]>, +{ + fn from(value: T) -> Self { + Self::from_slice(value.as_ref()) + } +} + #[cfg(test)] mod test { use super::*; @@ -181,4 +194,13 @@ mod test { assert_eq!(A.add(b'b'), AB); assert_eq!(AB.add(b'c'), ABC); } + + #[test] + fn is_empty() { + assert!(LetterSet::EMPTY.is_empty()); + assert!(!LetterSet::FULL.is_empty()); + assert!(!A.is_empty()); + assert!(!AB.is_empty()); + assert!(!BC.is_empty()); + } } diff --git a/src/main.rs b/src/main.rs index b27f6f6..04d57c2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,50 @@ +use std::{ + collections::{HashMap, hash_map::Entry}, + io::{self, BufRead, BufReader}, +}; + +use crate::letterset::LetterSet; + mod letterset; fn main() { - println!("Hello, world!"); + let dictionary: Vec = BufReader::new(io::stdin().lock()) + .lines() + .collect::>() + .unwrap(); + + let mut min_lengths: HashMap = HashMap::new(); + let min_length = solve(dictionary.as_slice(), &mut min_lengths, LetterSet::FULL); + println!("{min_length}"); +} + +// length doesn't include spaces. i think that's okay +fn solve( + dictionary: &[String], + min_lengths: &mut HashMap, + remaining: LetterSet, +) -> u16 { + if remaining.is_empty() { + return 0; + } + + if let Some(min) = min_lengths.get(&remaining) { + return *min; + } + + let min_length = dictionary + .iter() + .filter(|word| remaining != remaining.difference(LetterSet::from(word.as_bytes()))) + .map(|word| { + (u16::try_from(word.len()).unwrap()).saturating_add(solve( + dictionary, + min_lengths, + remaining.difference(LetterSet::from(word)), + )) + }) + .min() + .unwrap_or(u16::MAX); + + min_lengths.insert(remaining, min_length); + min_length }