diff options
Diffstat (limited to 'src/bin')
-rw-r--r-- | src/bin/day21.rs | 122 |
1 files changed, 122 insertions, 0 deletions
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())); +} |