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