use std::fs; use itertools::Itertools; fn solve_part1(insts: &Vec<&str>, init: &str) -> String { let mut chars: Vec = init.chars().collect(); for inst in insts { let mut next = chars.clone(); let words: Vec<&str> = inst.split_ascii_whitespace().collect(); if words[0] == "swap" { if words[1] == "position" { // Swap the characters at indices `i' and `j' let i: usize = words[2].parse().unwrap(); let j: usize = words[5].parse().unwrap(); next[i] = chars[j]; next[j] = chars[i]; } else if words[1] == "letter" { // Swap all occurrences of characters `x' and `y' let x = words[2].chars().nth(0).unwrap(); let y = words[5].chars().nth(0).unwrap(); for i in 0..next.len() { if next[i] == x { next[i] = y; } else if next[i] == y { next[i] = x; } } } } else if words[0] == "rotate" { if words[1] == "left" { let n: usize = words[2].parse().unwrap(); next.rotate_left(n % chars.len()); } else if words[1] == "right" { let n: usize = words[2].parse().unwrap(); next.rotate_right(n % chars.len()); } else if words[1] == "based" { // Get the index `i' of character `x' let x = words[6].chars().nth(0).unwrap(); let i = next.iter().position(|&c| c == x).unwrap(); // Rotate right by an amount determined by `i' let n = if i < 4 { i + 1 } else { i + 2 }; next.rotate_right(n % chars.len()); } } else if words[0] == "reverse" { let i: usize = words[2].parse().unwrap(); let j: usize = words[4].parse().unwrap(); next[i..j + 1].reverse(); } else if words[0] == "move" { let i: usize = words[2].parse().unwrap(); let j: usize = words[5].parse().unwrap(); let c = next.remove(i); next.insert(j, c); } chars = next; } chars.into_iter().collect() } fn solve_part2(insts: &Vec<&str>, target: &str) -> String { let init = vec!['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']; // The "good" approach would be to reverse the operations in `insts'. // I'm too lazy for that: I just go through all permutations of the // input characters, run `insts' as in part 1, and see if it's the one. for perm in init.into_iter().permutations(8) { let string: String = perm.iter().collect(); if solve_part1(insts, &string) == target { return string; } } String::new() // shouldn't happen } fn main() { // Read instructions from input text file let input = fs::read_to_string("input.txt").unwrap(); let insts = input.lines().collect(); // Part 1 gives "gfdhebac" for me println!("Part 1 solution: {}", solve_part1(&insts, "abcdefgh")); // Part 2 gives "dhaegfbc" for me println!("Part 2 solution: {}", solve_part2(&insts, "fbgdceah")); } #[cfg(test)] mod tests { use super::*; #[test] fn part1_example1() { let insts = vec![ "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!(solve_part1(&insts, "abcde"), "decab"); } }