advent_of_code/year2016/
day21.rs1use crate::common::permutation::all_permutations;
2use crate::input::Input;
3
4pub fn solve(input: &Input) -> Result<String, String> {
5 let mut password = [b'a', b'b', b'c', b'd', b'e', b'f', b'g', b'h'];
6 if input.is_part_one() {
7 scramble(input.text, &mut password)?;
8 Ok(password.iter().map(|&b| b as char).collect::<String>())
9 } else {
10 let desired = [b'f', b'b', b'g', b'd', b'c', b'e', b'a', b'h'];
12 let mut answer = None;
13 all_permutations(&mut password, &mut |permutation| {
14 let mut copy = [0, 0, 0, 0, 0, 0, 0, 0];
15 copy.copy_from_slice(permutation);
16 scramble(input.text, &mut copy)?;
17 if copy == desired {
18 answer = Some(permutation.iter().map(|&b| b as char).collect::<String>());
19 }
20 Ok(())
21 })?;
22
23 answer.ok_or_else(|| "No solution found".to_string())
24 }
25}
26
27fn scramble(input: &str, password: &mut [u8]) -> Result<(), String> {
28 let error_mapper = |_| "Invalid input";
29 for line in input.lines() {
30 let words = line.split(' ').collect::<Vec<_>>();
31 match words[0] {
32 "swap" => {
33 if words[1] == "position" {
34 let x = words[2].parse::<usize>().map_err(error_mapper)?;
35 let y = words[5].parse::<usize>().map_err(error_mapper)?;
36 password.swap(x, y);
37 } else {
38 let x = words[2].as_bytes()[0];
40 let y = words[5].as_bytes()[0];
41 for c in password.iter_mut() {
42 let orig = *c;
43 *c = if orig == x {
44 y
45 } else if orig == y {
46 x
47 } else {
48 orig
49 };
50 }
51 }
52 }
53 "rotate" => {
54 let rotation = if words[1] == "based" {
55 let letter = words[6].as_bytes()[0];
56 if let Some((idx, _)) =
57 password.iter().enumerate().find(|&(_idx, &c)| c == letter)
58 {
59 ((1 + idx + usize::from(idx >= 4)) % password.len()) as i32
60 } else {
61 return Err(format!(
62 "Unable to find letter for rotation: '{}'",
63 letter as char
64 ));
65 }
66 } else {
67 words[2].parse::<i32>().map_err(error_mapper)?
68 * if words[1] == "left" { -1 } else { 1 }
69 };
70
71 if rotation < 0 {
72 password.rotate_left((-rotation) as usize);
73 } else {
74 password.rotate_right(rotation as usize);
75 }
76 }
77 "reverse" => {
78 let x = words[2].parse::<usize>().map_err(error_mapper)?;
79 let y = words[4].parse::<usize>().map_err(error_mapper)?;
80 password[x..(y + 1)].reverse();
81 }
82 "move" => {
83 let x = words[2].parse::<usize>().map_err(error_mapper)?;
84 let y = words[5].parse::<usize>().map_err(error_mapper)?;
85 let mut buffer: Vec<u8> = password.to_vec();
86 let removed_letter = buffer.remove(x);
87 buffer.insert(y, removed_letter);
88 password.clone_from_slice(&buffer);
89 }
90 _ => {
91 return Err("Invalid input".to_string());
92 }
93 }
94 }
95 Ok(())
96}
97
98#[test]
99pub fn tests() {
100 let real_input = include_str!("day21_input.txt");
101 test_part_one!(real_input => "gcedfahb".to_string());
102 test_part_two!(real_input => "hegbdcfa".to_string());
103}