use std::collections::HashSet; fn main() { let input = "hxbxwxba"; println!("11a: {}", next_password(input)); println!("11b: {}", next_password(&next_password(input))); } fn has_straight(password: &str) -> bool { let mut prevprev = password.chars().next().unwrap().to_digit(36).unwrap(); let mut prev = password.chars().nth(1).unwrap().to_digit(36).unwrap(); for c in password.chars().skip(2) { let digit = c.to_digit(36).unwrap(); if prevprev + 1 == prev && prev + 1 == digit { return true; } prevprev = prev; prev = digit; } false } fn has_forbidden_letters(password: &str) -> bool { password.contains('i') || password.contains('o') || password.contains('l') } fn has_two_pairs(password: &str) -> bool { let mut pairs = HashSet::new(); let mut prev = password.chars().next().unwrap(); for c in password.chars().skip(1) { if prev == c { pairs.insert(c); } prev = c; } pairs.len() > 1 } fn valid_password(password: &str) -> bool { has_straight(password) && !has_forbidden_letters(password) && has_two_pairs(password) } fn inc_password_at_position(password: &str, pos: usize) -> String { let mut bytes = password.to_string().into_bytes(); bytes.reverse(); bytes[pos] += 1; if bytes[pos] > b'z' { bytes[pos] = b'a'; bytes.reverse(); let new_password = String::from_utf8(bytes.to_vec()).unwrap(); inc_password_at_position(&new_password, pos + 1) } else { bytes.reverse(); String::from_utf8(bytes.to_vec()).unwrap() } } fn next_password(password: &str) -> String { let mut password = inc_password_at_position(password, 0); while !valid_password(&password) { password = inc_password_at_position(&password, 0) } password } #[cfg(test)] mod tests { use super::*; #[test] fn test() { assert!(!valid_password("hijklmmn")); assert!(!valid_password("abbceffg")); assert!(!valid_password("abbcegjk")); assert_eq!(next_password("abcdefgh"), "abcdffaa"); assert_eq!(next_password("ghijklmn"), "ghjaabcc"); } }