This commit is contained in:
2016-12-22 13:57:16 +01:00
parent add430bbef
commit 831acafd8c
5 changed files with 506 additions and 0 deletions

285
2016/21/src/main.rs Normal file
View File

@@ -0,0 +1,285 @@
#[macro_use] extern crate lazy_static;
extern crate regex;
use std::io::{self, BufRead};
use std::str::FromStr;
use regex::Regex;
#[derive(Debug)]
pub enum Operation {
SwapPosition(usize, usize),
SwapLetter(char, char),
RotateLeft(usize),
RotateRight(usize),
RotatePosition(char),
ReversePosition(usize, usize),
MovePosition(usize, usize)
}
impl FromStr for Operation {
type Err = String;
fn from_str(s: &str) -> Result<Operation, Self::Err> {
lazy_static! {
static ref SWAP_P: Regex = Regex::new(r"^swap position (\d+) with position (\d+)$").unwrap();
static ref SWAP_L: Regex = Regex::new(r"^swap letter ([a-z]) with letter ([a-z])$").unwrap();
static ref ROTATE_L: Regex = Regex::new(r"^rotate left (\d+) steps?$").unwrap();
static ref ROTATE_R: Regex = Regex::new(r"^rotate right (\d+) steps?$").unwrap();
static ref ROTATE_P: Regex = Regex::new(r"^rotate based on position of letter ([a-z])$").unwrap();
static ref REVERSE: Regex = Regex::new(r"^reverse positions (\d+) through (\d+)$").unwrap();
static ref MOVE: Regex = Regex::new(r"^move position (\d+) to position (\d+)$").unwrap();
}
if let Some(caps) = SWAP_P.captures(s) {
let x = caps.at(1).unwrap().parse::<usize>().unwrap();
let y = caps.at(2).unwrap().parse::<usize>().unwrap();
return Ok(Operation::SwapPosition(x, y));
}
if let Some(caps) = SWAP_L.captures(s) {
let x = caps.at(1).unwrap().chars().nth(0).unwrap();
let y = caps.at(2).unwrap().chars().nth(0).unwrap();
return Ok(Operation::SwapLetter(x, y));
}
if let Some(caps) = ROTATE_L.captures(s) {
let x = caps.at(1).unwrap().parse::<usize>().unwrap();
return Ok(Operation::RotateLeft(x));
}
if let Some(caps) = ROTATE_R.captures(s) {
let x = caps.at(1).unwrap().parse::<usize>().unwrap();
return Ok(Operation::RotateRight(x));
}
if let Some(caps) = ROTATE_P.captures(s) {
let x = caps.at(1).unwrap().chars().nth(0).unwrap();
return Ok(Operation::RotatePosition(x));
}
if let Some(caps) = REVERSE.captures(s) {
let x = caps.at(1).unwrap().parse::<usize>().unwrap();
let y = caps.at(2).unwrap().parse::<usize>().unwrap();
return Ok(Operation::ReversePosition(x, y));
}
if let Some(caps) = MOVE.captures(s) {
let x = caps.at(1).unwrap().parse::<usize>().unwrap();
let y = caps.at(2).unwrap().parse::<usize>().unwrap();
return Ok(Operation::MovePosition(x, y));
}
Err(s.to_owned())
}
}
pub fn op_swap_position(input: &str, x: usize, y: usize) -> String {
let chars = input.chars()
.enumerate()
.filter(|&(i, _)| i == x || i == y)
.map(|(_, c)| c)
.collect::<Vec<_>>();
input.chars()
.enumerate()
.map(|(i, c)| {
if i == x {
chars[if x < y { 1 } else { 0 }]
} else if i == y {
chars[if x < y { 0 } else { 1 }]
} else {
c
}
})
.collect::<String>()
}
pub fn op_swap_letter(input: &str, x: char, y: char) -> String {
input.chars()
.map(|c| {
if c == x {
y
} else if c == y {
x
} else {
c
}
})
.collect::<String>()
}
pub fn op_rotate_left(input: &str, x: usize) -> String {
let (left, right) = input.split_at(x % input.len());
right.to_owned() + left
}
pub fn op_rotate_right(input: &str, x: usize) -> String {
op_rotate_left(input, input.len() - (x % input.len()))
}
pub fn op_rotate_position(input: &str, x: char) -> String {
if let Some(position) = input.find(x) {
let delta = if position < 4 { 1 } else { 2 };
op_rotate_right(input, position + delta)
} else {
input.to_owned()
}
}
pub fn op_reverse_position(input: &str, x: usize, y: usize) -> String {
let (center, right) = input.split_at(y + 1);
let (left, center) = center.split_at(x);
left.to_owned() + center.chars().rev().collect::<String>().as_str() + right
}
pub fn op_move_position(input: &str, x: usize, y: usize) -> String {
let mut output = input.to_owned();
let c = output.remove(x);
output.insert(y, c);
output
}
fn main() {
let input = "abcdefgh";
let stdin = io::stdin();
let operations = stdin.lock().lines()
.filter_map(|line| line.ok())
.map(|line| line.parse::<Operation>().unwrap())
.collect::<Vec<_>>();;
// Part 1.
let mut output = input.to_owned();
for operation in operations.iter() {
output = match operation {
&Operation::SwapPosition(x, y) => op_swap_position(&output, x, y),
&Operation::SwapLetter(x, y) => op_swap_letter(&output, x, y),
&Operation::RotateLeft(x) => op_rotate_left(&output, x),
&Operation::RotateRight(x) => op_rotate_right(&output, x),
&Operation::RotatePosition(x) => op_rotate_position(&output, x),
&Operation::ReversePosition(x, y) => op_reverse_position(&output, x, y),
&Operation::MovePosition(x, y) => op_move_position(&output, x, y),
};
}
println!("output={}", output);
// Part 2.
let mut state = "aaaaaaaa".to_owned();
loop {
let mut output = state.clone();
for operation in operations.iter() {
output = match operation {
&Operation::SwapPosition(x, y) => op_swap_position(&output, x, y),
&Operation::SwapLetter(x, y) => op_swap_letter(&output, x, y),
&Operation::RotateLeft(x) => op_rotate_left(&output, x),
&Operation::RotateRight(x) => op_rotate_right(&output, x),
&Operation::RotatePosition(x) => op_rotate_position(&output, x),
&Operation::ReversePosition(x, y) => op_reverse_position(&output, x, y),
&Operation::MovePosition(x, y) => op_move_position(&output, x, y),
};
}
if output == "fbgdceah".to_owned() {
break;
}
state = state.chars()
.rev()
.scan(true, |rotate, c| {
if *rotate {
if c < 'h' {
*rotate = false;
Some(((c as u8) + 1) as char)
} else {
Some('a')
}
} else {
Some(c)
}
})
.collect::<Vec<_>>()
.iter()
.rev()
.map(|c| *c)
.collect::<String>();
}
println!("input={}", state);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_op_swap_position() {
assert_eq!("ebcda".to_owned(), op_swap_position("abcde", 4, 0));
assert_eq!("ebcda".to_owned(), op_swap_position("abcde", 0, 4));
assert_eq!("adcbe".to_owned(), op_swap_position("abcde", 1, 3));
assert_eq!("adcbe".to_owned(), op_swap_position("abcde", 3, 1));
}
#[test]
fn test_op_swap_letter() {
assert_eq!("edcba".to_owned(), op_swap_letter("ebcda", 'd', 'b'));
}
#[test]
fn test_op_rotate_left() {
assert_eq!("ebcda".to_owned(), op_rotate_left("ebcda", 0));
assert_eq!("bcdae".to_owned(), op_rotate_left("ebcda", 1));
}
#[test]
fn test_op_rotate_right() {
assert_eq!("ebcda".to_owned(), op_rotate_right("ebcda", 0));
assert_eq!("aebcd".to_owned(), op_rotate_right("ebcda", 1));
}
#[test]
fn test_op_rotate_position() {
assert_eq!("ecabd".to_owned(), op_rotate_position("abdec", 'b'));
assert_eq!("decab".to_owned(), op_rotate_position("ecabd", 'd'));
}
#[test]
fn test_op_reverse_position() {
assert_eq!("abcde".to_owned(), op_reverse_position("edcba", 0, 4));
assert_eq!("ebcda".to_owned(), op_reverse_position("edcba", 1, 3));
assert_eq!("decba".to_owned(), op_reverse_position("edcba", 0, 1));
}
#[test]
fn test_op_move_position() {
assert_eq!("bdeac".to_owned(), op_move_position("bcdea", 1, 4));
assert_eq!("abdec".to_owned(), op_move_position("bdeac", 3, 0));
}
}