mirror of
https://github.com/RussellChamp/advent-of-code-2016.git
synced 2026-10-27 23:32:30 +00:00
245 lines
9.1 KiB
Rust
245 lines
9.1 KiB
Rust
extern crate regex;
|
|||
|
|
|
||
|
|
use std::io::Read;
|
||
|
|
use std::fs::File;
|
||
|
|
use regex::Regex;
|
||
|
|
use std::cmp;
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, Copy)]
|
||
|
|
enum Direction {
|
||
|
|
Right,
|
||
|
|
Left
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug)]
|
||
|
|
enum Step {
|
||
|
|
SwapPos { from: usize, to: usize },
|
||
|
|
SwapLet { from: char, to: char },
|
||
|
|
RotatePos { dir: Direction, value: usize },
|
||
|
|
RotateLet { from: char },
|
||
|
|
Reverse { from: usize, to: usize },
|
||
|
|
MovePos { from: usize, to: usize },
|
||
|
|
}
|
||
|
|
|
||
|
|
fn swap_position(passcode: String, from: usize, to: usize) -> String {
|
||
|
|
let (low, high) = (cmp::min(from, to), cmp::max(from, to));
|
||
|
|
let mut new_passcode = passcode[0..low].to_string();
|
||
|
|
|
||
|
|
let low_char = passcode.chars().clone().nth(low).unwrap();
|
||
|
|
let high_char = passcode.chars().clone().nth(high).unwrap();
|
||
|
|
|
||
|
|
new_passcode.push(high_char);
|
||
|
|
if low + 1 < high {
|
||
|
|
new_passcode.push_str(&passcode[low+1..high]);
|
||
|
|
}
|
||
|
|
new_passcode.push(low_char);
|
||
|
|
if high < passcode.len() {
|
||
|
|
new_passcode.push_str(&passcode[high+1..]);
|
||
|
|
}
|
||
|
|
//println!("{} -> {}", passcode, new_passcode);
|
||
|
|
new_passcode
|
||
|
|
}
|
||
|
|
|
||
|
|
fn swap_letter(passcode: String, from: char, to: char) -> String {
|
||
|
|
let pos_from = passcode.chars().position(|c| c == from).unwrap();
|
||
|
|
let pos_to = passcode.chars().position(|c| c == to).unwrap();
|
||
|
|
swap_position(passcode, pos_from, pos_to)
|
||
|
|
}
|
||
|
|
|
||
|
|
fn rotate_position(passcode: String, dir: Direction, value: usize) -> String {
|
||
|
|
let mut new_passcode = String::new();
|
||
|
|
let shift = value % passcode.len(); //unless we shift by too much
|
||
|
|
match dir {
|
||
|
|
Direction::Right => {
|
||
|
|
//the last 'value' characters and then the rest
|
||
|
|
let split_idx = passcode.len()-shift;
|
||
|
|
new_passcode.push_str(&passcode[split_idx..]);
|
||
|
|
new_passcode.push_str(&passcode[..split_idx]);
|
||
|
|
},
|
||
|
|
Direction::Left => {
|
||
|
|
new_passcode.push_str(&passcode[shift..]);
|
||
|
|
new_passcode.push_str(&passcode[..shift]);
|
||
|
|
},
|
||
|
|
}
|
||
|
|
//println!("{} -({} {:?})-> {}", passcode, value, dir, new_passcode);
|
||
|
|
new_passcode
|
||
|
|
}
|
||
|
|
|
||
|
|
fn rotate_letter(passcode: String, from: char) -> String {
|
||
|
|
//rotate to the right based on 1 + idx of letter + 1 if idx > 3
|
||
|
|
let pos = passcode.chars().position(|c| c == from).unwrap();
|
||
|
|
if pos > 3 {
|
||
|
|
return rotate_position(passcode, Direction::Right, 2 + pos);
|
||
|
|
} else {
|
||
|
|
return rotate_position(passcode, Direction::Right, 1 + pos);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
fn un_rotate_letter(passcode: String, from: char) -> String {
|
||
|
|
//find the letter
|
||
|
|
passcode
|
||
|
|
}
|
||
|
|
|
||
|
|
fn reverse(passcode: String, from: usize, to: usize) -> String {
|
||
|
|
let mut new_passcode = String::from(&passcode[..from]);
|
||
|
|
for c in passcode[from..to+1].chars().rev() {
|
||
|
|
new_passcode.push(c);
|
||
|
|
}
|
||
|
|
new_passcode.push_str(&passcode[to+1..]);
|
||
|
|
//println!("{} -> {}", passcode, new_passcode);
|
||
|
|
new_passcode
|
||
|
|
}
|
||
|
|
|
||
|
|
fn move_position(passcode: String, from: usize, to: usize) -> String {
|
||
|
|
let mut new_passcode = String::new();
|
||
|
|
if from < to {
|
||
|
|
// [..from][from+1..to+1][from][to.1..]
|
||
|
|
new_passcode.push_str(&passcode[..from]);
|
||
|
|
new_passcode.push_str(&passcode[from+1..to+1]);
|
||
|
|
new_passcode.push_str(&passcode[from..from+1]);
|
||
|
|
new_passcode.push_str(&passcode[to+1..]);
|
||
|
|
} else {
|
||
|
|
// [..to][from][to..from][from+1..]
|
||
|
|
new_passcode.push_str(&passcode[..to]);
|
||
|
|
new_passcode.push_str(&passcode[from..from+1]);
|
||
|
|
new_passcode.push_str(&passcode[to..from]);
|
||
|
|
new_passcode.push_str(&passcode[from+1..]);
|
||
|
|
}
|
||
|
|
//println!("{} -> {}", passcode, new_passcode);
|
||
|
|
new_passcode
|
||
|
|
}
|
||
|
|
|
||
|
|
fn main() {
|
||
|
|
let re_swap_pos = Regex::new(r"swap position (\d+) with position (\d+)").unwrap();
|
||
|
|
let re_swap_let = Regex::new(r"swap letter ([:alpha:]) with letter ([:alpha:])").unwrap();
|
||
|
|
let re_rotate_pos = Regex::new(r"rotate (left|right) (\d+) step[s]{0,1}").unwrap();
|
||
|
|
let re_rotate_let = Regex::new(r"rotate based on position of letter ([:alpha:])").unwrap();
|
||
|
|
let re_reverse = Regex::new(r"reverse positions (\d+) through (\d+)").unwrap();
|
||
|
|
let re_move_pos = Regex::new(r"move position (\d+) to position (\d)").unwrap();
|
||
|
|
|
||
|
|
let mut file = File::open("./data").expect("could not open file");
|
||
|
|
let mut input = String::new();
|
||
|
|
file.read_to_string(&mut input).expect("could not read file");
|
||
|
|
|
||
|
|
let mut steps: Vec<Step> = Vec::new(); //translate all the instructions
|
||
|
|
|
||
|
|
for line in input.lines() {
|
||
|
|
if re_swap_pos.is_match(line) {
|
||
|
|
let cap = re_swap_pos.captures(line).unwrap();
|
||
|
|
steps.push(Step::SwapPos { from: cap.at(1).unwrap().parse().unwrap(), to: cap.at(2).unwrap().parse().unwrap() });
|
||
|
|
}
|
||
|
|
else if re_swap_let.is_match(line) {
|
||
|
|
let cap = re_swap_let.captures(line).unwrap();
|
||
|
|
steps.push(Step::SwapLet { from: cap.at(1).unwrap().chars().next().unwrap(), to: cap.at(2).unwrap().chars().next().unwrap() });
|
||
|
|
}
|
||
|
|
else if re_rotate_pos.is_match(line) {
|
||
|
|
let cap = re_rotate_pos.captures(line).unwrap();
|
||
|
|
let direction = match cap.at(1).unwrap() {
|
||
|
|
"left" => Direction::Left,
|
||
|
|
_ => Direction::Right,
|
||
|
|
};
|
||
|
|
let value = cap.at(2).unwrap().parse().unwrap();
|
||
|
|
|
||
|
|
steps.push(Step::RotatePos { dir: direction, value: value });
|
||
|
|
}
|
||
|
|
else if re_rotate_let.is_match(line) {
|
||
|
|
let cap = re_rotate_let.captures(line).unwrap();
|
||
|
|
steps.push(Step::RotateLet { from: cap.at(1).unwrap().chars().next().unwrap() });
|
||
|
|
}
|
||
|
|
else if re_reverse.is_match(line) {
|
||
|
|
let cap = re_reverse.captures(line).unwrap();
|
||
|
|
steps.push(Step::Reverse { from: cap.at(1).unwrap().parse().unwrap(), to: cap.at(2).unwrap().parse().unwrap() });
|
||
|
|
}
|
||
|
|
else if re_move_pos.is_match(line) {
|
||
|
|
let cap = re_move_pos.captures(line).unwrap();
|
||
|
|
steps.push(Step::MovePos { from: cap.at(1).unwrap().parse().unwrap(), to: cap.at(2).unwrap().parse().unwrap() });
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
panic!("Unknown pattern! {}", line);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// let mut passcode = String::from("abcdefgh");
|
||
|
|
|
||
|
|
// println!("All Steps: ");
|
||
|
|
// for step in steps {
|
||
|
|
// passcode = match step {
|
||
|
|
// Step::SwapPos { from, to } => { swap_position(passcode, from, to) },
|
||
|
|
// Step::SwapLet { from, to } => { swap_letter(passcode, from, to) },
|
||
|
|
// Step::RotatePos { dir, value } => { rotate_position(passcode, dir, value) },
|
||
|
|
// Step::RotateLet { from } => { rotate_letter(passcode, from) },
|
||
|
|
// Step::Reverse { from, to } => { reverse(passcode, from, to) },
|
||
|
|
// Step::MovePos { from, to } => { move_position(passcode, from, to) },
|
||
|
|
// };
|
||
|
|
// //println!("{} -> ", passcode);
|
||
|
|
// //println!("{:?}", step);
|
||
|
|
// }
|
||
|
|
// println!("Part 1: Passcode is {}", passcode);
|
||
|
|
|
||
|
|
let mut existing = String::from("fbgdceah");
|
||
|
|
for step in steps.iter().rev() {
|
||
|
|
existing = match *step {
|
||
|
|
Step::SwapPos { from, to } => { swap_position(existing, from, to) }, //unaffected
|
||
|
|
Step::SwapLet { from, to } => { swap_letter(existing, from, to) }, //unaffected
|
||
|
|
Step::RotatePos { dir, value } => {
|
||
|
|
let undir = match dir {
|
||
|
|
Direction::Right => Direction::Left,
|
||
|
|
Direction::Left => Direction::Right
|
||
|
|
};
|
||
|
|
rotate_position(existing, undir, value)
|
||
|
|
}, //mostly unaffected
|
||
|
|
Step::RotateLet { from } => { un_rotate_letter(existing, from) },
|
||
|
|
Step::Reverse { from, to } => { reverse(existing, from, to) }, //unaffected
|
||
|
|
Step::MovePos { from, to } => { move_position(existing, to, from) }, //mostly unaffected
|
||
|
|
}
|
||
|
|
}
|
||
|
|
println!("Part 2: Decyphered passcode is {}", existing);
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_swap_position() {
|
||
|
|
assert_eq!(swap_position("abcd".to_string(), 0, 2), "cbad");
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_swap_letter() {
|
||
|
|
assert_eq!(swap_letter("abcd".to_string(), 'b', 'd'), "adcb");
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_rotate_position() {
|
||
|
|
assert_eq!(rotate_position("abcd".to_string(), Direction::Right, 2), "cdab");
|
||
|
|
assert_eq!(rotate_position("abcd".to_string(), Direction::Left, 1), "bcda");
|
||
|
|
assert_eq!(rotate_position("abcd".to_string(), Direction::Right, 8), "abcd");
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_rotate_letter() {
|
||
|
|
assert_eq!(rotate_letter("abcd".to_string(), 'b'), "cdab");
|
||
|
|
assert_eq!(rotate_letter("abcd".to_string(), 'b'), rotate_position("abcd".to_string(), Direction::Right, 2));
|
||
|
|
assert_eq!(rotate_letter("abcdefgh".to_string(), 'f'), "bcdefgha");
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_reverse() {
|
||
|
|
assert_eq!(reverse("abcd".to_string(), 1, 2), "acbd");
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_move_position() {
|
||
|
|
assert_eq!(move_position("abcdefg".to_string(), 1, 4), "acdebfg");
|
||
|
|
assert_eq!(move_position("abcdefg".to_string(), 4, 1), "aebcdfg");
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_undo_move_position() {
|
||
|
|
assert_eq!(move_position(move_position("abcdefg".to_string(), 1, 4), 4, 1), "abcdefg");
|
||
|
|
assert_eq!(move_position(move_position("abcdefg".to_string(), 4, 1), 1, 4), "abcdefg");
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_un_rotate_letter() {
|
||
|
|
assert_eq!(un_rotate_letter("abcdefg".to_string(), 'c'), "abcdefg");
|
||
|
|
assert_eq!(un_rotate_letter(rotate_letter("abcdefg".to_string(), 'c'), 'c'), "abcdefg");
|
||
|
|
}
|