diff --git a/rust/src/day_11.rs b/rust/src/day_11.rs new file mode 100644 index 0000000..287bd9e --- /dev/null +++ b/rust/src/day_11.rs @@ -0,0 +1,104 @@ +use std::collections::HashSet; + +#[derive(Debug, Eq, PartialEq)] +pub struct Password(String); +impl Password { + pub fn new(s: &str) -> Self { + Password(s.into()) + } + + pub fn is_valid(&self) -> bool { + self.has_increasing_straight() && !self.has_confusing_chars() && + self.has_different_nonoverlapping_pairs() + } + + pub fn next(&self) -> Self { + StringIncrementor::new(&self.0).map(|x| Self::new(&x)).find(|ref x| { + x.is_valid() + }).unwrap() + } + + fn has_increasing_straight(&self) -> bool { + self.0 + .chars() + .collect::>() + .windows(3) + .any(|w| w.windows(2).all(|x| (x[1] as i8) - (x[0] as i8) == 1)) + } + + fn has_confusing_chars(&self) -> bool { + self.0.chars().any(|c| ['i', 'l', 'o'].contains(&c)) + } + + fn has_different_nonoverlapping_pairs(&self) -> bool { + let slice = self.0.chars().collect::>(); + slice.windows(2).filter_map(|x| { + if x[0] == x[1] { Some(x[0]) } else { None } + }).collect::>().len() > 1 + } +} + +impl From for String { + fn from(p: Password) -> String { + p.0 + } +} + +struct StringIncrementor { + s: String, +} + +impl StringIncrementor { + fn new(s: &str) -> Self { + StringIncrementor{s: s.into()} + } +} + +impl Iterator for StringIncrementor { + type Item = String; + + fn next(&mut self) -> Option { + self.s = self.s.chars() + .rev() + .scan(true, |carry, x| { + if !*carry { + return Some(x); + } + + if x == 'z' { + Some('a') + } else { + *carry = false; + Some((x as u8 + 1) as char) + } + }) + .collect::>() + .iter() + .map(|&x| x) + .rev() + .collect(); + Some(self.s.clone()) + } +} + +#[test] +fn test_string_incrementor() { + assert_eq!(StringIncrementor::new("abcdefgh").next(), Some("abcdefgi".into())); + assert_eq!(StringIncrementor::new("az").next(), Some("ba".into())); +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_password() { + assert!(!Password::new("hijklmmn").is_valid()); + assert!(!Password::new("abbceffg").is_valid()); + assert!(!Password::new("abbcegjk").is_valid()); + assert!(!Password::new("ghjaaaaa").is_valid()); + + assert_eq!(Password::new("abcdefgh").next(), Password::new("abcdffaa")); + assert_eq!(Password::new("ghijklmn").next(), Password::new("ghjaabcc")); + } +} diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 8cb05f2..54bb85a 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -14,3 +14,4 @@ pub mod day_07; pub mod day_08; pub mod day_09; pub mod day_10; +pub mod day_11; diff --git a/rust/src/main.rs b/rust/src/main.rs index 30cf1af..691196d 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -20,7 +20,8 @@ fn main() { Some("7") => day_07::solve(&input, "a").to_string(), Some("8") => day_08::solve(&input).to_string(), Some("9") => day_09::solve(&input).to_string(), - _ => day_10::solve(&input), + Some("10") => day_10::solve(&input).to_string(), + _ => day_11::Password::new("cqjxjnds").next().into(), }; println!("{}", solution);