2016/21
This commit is contained in:
285
2016/21/src/main.rs
Normal file
285
2016/21/src/main.rs
Normal 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));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user