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