1use crate::util::parse::*;
6
7#[derive(Clone, Copy)]
8pub enum Op {
9 SwapPosition(usize, usize),
10 SwapLetter(u8, u8),
11 RotateLeft(usize),
12 RotateRight(usize),
13 RotateLetterLeft(u8),
14 RotateLetterRight(u8),
15 Reverse(usize, usize),
16 Move(usize, usize),
17}
18
19impl Op {
20 fn from(line: &str) -> Op {
21 let tokens: Vec<_> = line.split_ascii_whitespace().collect();
22 let digit = |i: usize| tokens[i].unsigned();
23 let letter = |i: usize| tokens[i].as_bytes()[0];
24
25 match tokens[0] {
26 "reverse" => Op::Reverse(digit(2), digit(4)),
27 "move" => Op::Move(digit(2), digit(5)),
28 _ => match tokens[1] {
29 "position" => Op::SwapPosition(digit(2), digit(5)),
30 "letter" => Op::SwapLetter(letter(2), letter(5)),
31 "left" => Op::RotateLeft(digit(2)),
32 "right" => Op::RotateRight(digit(2)),
33 "based" => Op::RotateLetterRight(letter(6)),
34 _ => unreachable!(),
35 },
36 }
37 }
38
39 fn transform(self, password: &mut Vec<u8>) {
40 let position = |a: u8| password.iter().position(|&b| a == b).unwrap();
41
42 match self {
43 Op::SwapPosition(first, second) => password.swap(first, second),
44 Op::SwapLetter(first, second) => {
45 let first = position(first);
46 let second = position(second);
47 password.swap(first, second);
48 }
49 Op::RotateLeft(first) => password.rotate_left(first),
50 Op::RotateRight(first) => password.rotate_right(first),
51 Op::RotateLetterLeft(first) => {
54 let first = position(first);
55 for i in 0..password.len() {
56 let second = if i >= 4 { 2 } else { 1 };
57 let third = (2 * i + second) % password.len();
58 if first == third {
59 if i < first {
60 password.rotate_left(first - i);
61 } else {
62 password.rotate_right(i - first);
63 }
64 }
65 }
66 }
67 Op::RotateLetterRight(first) => {
68 let first = position(first);
69 let second = if first >= 4 { 2 } else { 1 };
70 let third = (first + second) % password.len();
71 password.rotate_right(third);
72 }
73 Op::Reverse(first, second) => password[first..=second].reverse(),
74 Op::Move(first, second) => {
75 let letter = password.remove(first);
76 password.insert(second, letter);
77 }
78 }
79 }
80
81 fn inverse(self) -> Op {
82 match self {
83 Op::RotateLeft(first) => Op::RotateRight(first),
84 Op::RotateRight(first) => Op::RotateLeft(first),
85 Op::RotateLetterLeft(first) => Op::RotateLetterRight(first),
86 Op::RotateLetterRight(first) => Op::RotateLetterLeft(first),
87 Op::Move(first, second) => Op::Move(second, first),
88 other => other,
90 }
91 }
92}
93
94pub fn parse(input: &str) -> Vec<Op> {
95 input.lines().map(Op::from).collect()
96}
97
98pub fn part1(input: &[Op]) -> String {
99 scramble(input, b"abcdefgh")
100}
101
102pub fn part2(input: &[Op]) -> String {
103 unscramble(input, b"fbgdceah")
104}
105
106pub fn scramble(input: &[Op], slice: &[u8]) -> String {
107 let mut password = slice.to_vec();
108
109 for op in input {
110 op.transform(&mut password);
111 }
112
113 String::from_utf8(password).unwrap()
114}
115
116pub fn unscramble(input: &[Op], slice: &[u8]) -> String {
117 let mut password = slice.to_vec();
118
119 for op in input.iter().rev() {
120 op.inverse().transform(&mut password);
121 }
122
123 String::from_utf8(password).unwrap()
124}