summary refs log tree commit diff homepage
diff options
context:
space:
mode:
-rw-r--r--input/day21.txt100
-rw-r--r--src/bin/day21.rs122
2 files changed, 222 insertions, 0 deletions
diff --git a/input/day21.txt b/input/day21.txt
new file mode 100644
index 0000000..68bb697
--- /dev/null
+++ b/input/day21.txt
@@ -0,0 +1,100 @@
+swap position 5 with position 6
+reverse positions 1 through 6
+rotate right 7 steps
+rotate based on position of letter c
+rotate right 7 steps
+reverse positions 0 through 4
+swap letter f with letter h
+reverse positions 1 through 2
+move position 1 to position 0
+rotate based on position of letter f
+move position 6 to position 3
+reverse positions 3 through 6
+rotate based on position of letter c
+rotate based on position of letter b
+move position 2 to position 4
+swap letter b with letter d
+move position 1 to position 6
+move position 7 to position 1
+swap letter f with letter c
+move position 2 to position 3
+swap position 1 with position 7
+reverse positions 3 through 5
+swap position 1 with position 4
+move position 4 to position 7
+rotate right 4 steps
+reverse positions 3 through 6
+move position 0 to position 6
+swap position 3 with position 5
+swap letter e with letter h
+rotate based on position of letter c
+swap position 4 with position 7
+reverse positions 0 through 5
+rotate right 5 steps
+rotate left 0 steps
+rotate based on position of letter f
+swap letter e with letter b
+rotate right 2 steps
+rotate based on position of letter c
+swap letter a with letter e
+rotate left 4 steps
+rotate left 0 steps
+move position 6 to position 7
+rotate right 2 steps
+rotate left 6 steps
+rotate based on position of letter d
+swap letter a with letter b
+move position 5 to position 4
+reverse positions 0 through 7
+rotate left 3 steps
+rotate based on position of letter e
+rotate based on position of letter h
+swap position 4 with position 6
+reverse positions 4 through 5
+reverse positions 5 through 7
+rotate left 3 steps
+move position 7 to position 2
+move position 3 to position 4
+swap letter b with letter d
+reverse positions 3 through 4
+swap letter e with letter a
+rotate left 4 steps
+swap position 3 with position 4
+swap position 7 with position 5
+rotate right 1 step
+rotate based on position of letter g
+reverse positions 0 through 3
+swap letter g with letter b
+rotate based on position of letter b
+swap letter a with letter c
+swap position 0 with position 2
+reverse positions 1 through 3
+rotate left 7 steps
+swap letter f with letter a
+move position 5 to position 0
+reverse positions 1 through 5
+rotate based on position of letter d
+rotate based on position of letter c
+rotate left 2 steps
+swap letter b with letter a
+swap letter f with letter c
+swap letter h with letter f
+rotate based on position of letter b
+rotate left 3 steps
+swap letter b with letter h
+reverse positions 1 through 7
+rotate based on position of letter h
+swap position 1 with position 5
+rotate left 1 step
+rotate based on position of letter h
+reverse positions 0 through 1
+swap position 5 with position 7
+reverse positions 0 through 2
+reverse positions 1 through 3
+move position 1 to position 4
+reverse positions 1 through 3
+rotate left 1 step
+swap position 4 with position 1
+move position 1 to position 3
+rotate right 2 steps
+move position 0 to position 5
\ No newline at end of file
diff --git a/src/bin/day21.rs b/src/bin/day21.rs
new file mode 100644
index 0000000..c195c08
--- /dev/null
+++ b/src/bin/day21.rs
@@ -0,0 +1,122 @@
+use std::io::{self, Read};
+
+#[derive(Debug, Clone, Copy)]
+enum Operation {
+    SwapPosition(usize, usize),
+    SwapLetter(u8, u8),
+    RotateLeft(usize),
+    RotateRight(usize),
+    RotateLetter(u8),
+    Reverse(usize, usize),
+    Move(usize, usize),
+}
+
+impl Operation {
+    fn apply(self, slice: &mut [u8]) {
+        match self {
+            Operation::SwapPosition(i, j) => slice.swap(i, j),
+            Operation::SwapLetter(a, b) => {
+                let i = slice.iter().position(|&x| x == a).unwrap();
+                let j = slice.iter().position(|&x| x == b).unwrap();
+                slice.swap(i, j);
+            },
+            Operation::RotateLeft(n) => {
+                let n = n % slice.len();
+                slice[0..n].reverse();
+                slice[n..].reverse();
+                slice.reverse();
+            },
+            Operation::RotateRight(n) => {
+                let n = n % slice.len();
+                slice.reverse();
+                slice[0..n].reverse();
+                slice[n..].reverse();
+            },
+            Operation::RotateLetter(a) => {
+                let mut n = 1 + slice.iter().position(|&x| x == a).unwrap();
+                if n >= 4 { n += 1 }
+                n %= slice.len();
+                slice.reverse();
+                slice[0..n].reverse();
+                slice[n..].reverse();
+            },
+            Operation::Reverse(i, j) => slice[i..(j + 1)].reverse(),
+            Operation::Move(i, j) if i < j => {
+                let a = slice[i];
+                for k in i..j {
+                    slice[k] = slice[k + 1];
+                }
+                slice[j] = a;
+            },
+            Operation::Move(i, j) => {
+                let a = slice[i];
+                for k in (j..i).rev() {
+                    slice[k + 1] = slice[k];
+                }
+                slice[j] = a;
+            },
+        }
+    }
+}
+
+impl<'a> From<&'a str> for Operation {
+    fn from(s: &'a str) -> Self {
+        let mut iter = s.split_whitespace();
+        match (iter.next().unwrap(), iter.next().unwrap()) {
+            ("swap", "position") => Operation::SwapPosition(
+                iter.next().unwrap().parse().unwrap(),
+                iter.nth(2).unwrap().parse().unwrap(),
+            ),
+            ("swap", "letter") => Operation::SwapLetter(
+                iter.next().unwrap().as_bytes()[0],
+                iter.nth(2).unwrap().as_bytes()[0],
+            ),
+            ("rotate", "left") => Operation::RotateLeft(iter.next().unwrap().parse().unwrap()),
+            ("rotate", "right") => Operation::RotateRight(iter.next().unwrap().parse().unwrap()),
+            ("rotate", "based") => Operation::RotateLetter(iter.nth(4).unwrap().as_bytes()[0]),
+            ("reverse", _) => Operation::Reverse(
+                iter.next().unwrap().parse().unwrap(),
+                iter.nth(1).unwrap().parse().unwrap(),
+            ),
+            ("move", _) => Operation::Move(
+                iter.next().unwrap().parse().unwrap(),
+                iter.nth(2).unwrap().parse().unwrap(),
+            ),
+            (x, y) => panic!("invalid operation {} {}", x, y),
+        }
+    }
+}
+
+fn solve(password: &str, input: &str) -> String {
+    let mut password = password.as_bytes().to_owned();
+
+    for operation in input.lines().map(Operation::from) {
+        print!("{} ", std::str::from_utf8(&password).unwrap());
+        operation.apply(&mut password);
+        println!("{:^20} {}", format!("{:?}", operation), std::str::from_utf8(&password).unwrap());
+    }
+
+    String::from_utf8(password).unwrap()
+}
+
+fn main() {
+    let mut input = String::new();
+    io::stdin().read_to_string(&mut input).unwrap();
+
+    println!("Part 1: {}", solve("abcdefgh", &input));
+}
+
+#[test]
+fn part1() {
+    let input = "
+swap position 4 with position 0
+swap letter d with letter b
+reverse positions 0 through 4
+rotate left 1 step
+move position 1 to position 4
+move position 3 to position 0
+rotate based on position of letter b
+rotate based on position of letter d
+";
+    assert_eq!("decab", solve("abcde", input.trim()));
+}