advent_of_code/year2015/
day11.rs1use crate::input::Input;
2use std::collections::HashSet;
3
4fn is_valid(password: &[u8]) -> bool {
5 if !password
8 .windows(3)
9 .any(|w| w[1] == w[0] + 1 && w[2] == w[1] + 1)
10 {
11 return false;
12 }
13
14 if password.iter().any(|b| [b'i', b'o', b'l'].contains(b)) {
16 return false;
17 }
18
19 let mut pairs = HashSet::new();
21 for window in password.windows(2) {
22 if window[0] == window[1] {
23 pairs.insert(window);
24 }
25 }
26 pairs.len() > 1
27}
28
29pub fn solve(input: &Input) -> Result<String, String> {
30 let bytes = input.text.as_bytes();
31 if bytes.len() != 8 || bytes.iter().any(|b| !b.is_ascii_lowercase()) {
32 return Err("Invalid current password (not 8 lower ASCII characters)".to_string());
33 }
34
35 let mut current_password = [0_u8; 8];
36 current_password.copy_from_slice(bytes);
37 let mut return_next_password = input.is_part_one();
38
39 'outer: loop {
40 if is_valid(¤t_password) {
41 if return_next_password {
42 return Ok(std::str::from_utf8(¤t_password)
43 .map_err(|_| "Invalid utf-8 in password")?
44 .to_string());
45 } else {
46 return_next_password = true;
47 }
48 }
49 if current_password[7] == b'z' {
50 for idx in (0..=6).rev() {
51 if current_password[idx] != b'z' {
52 current_password[idx] += 1;
53 for c in current_password.iter_mut().skip(idx + 1) {
54 *c = b'a';
55 }
56 continue 'outer;
57 }
58 }
59 return Err("Unable to generate valid password".to_string());
60 } else {
61 current_password[7] += 1;
62 }
63 }
64}
65
66#[test]
67pub fn tests() {
68 test_part_one!("abcdefgh" => "abcdffaa".to_string());
69
70 let real_input = include_str!("day11_input.txt");
71 test_part_one!(real_input => "hepxxyzz".to_string());
72 test_part_two!(real_input => "heqaabcc".to_string());
73}