solution: day 21
This commit is contained in:
parent
9c0653f39e
commit
9f353660f1
@ -18,7 +18,7 @@ pub mod d17;
|
||||
pub mod d18;
|
||||
pub mod d19;
|
||||
pub mod d20;
|
||||
// pub mod d21;
|
||||
pub mod d21;
|
||||
// pub mod d22;
|
||||
// pub mod d23;
|
||||
// pub mod d24;
|
||||
|
||||
151
src/days/d21.rs
Normal file
151
src/days/d21.rs
Normal file
@ -0,0 +1,151 @@
|
||||
#![allow(non_upper_case_globals)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
pub type I = Vec<Inst>;
|
||||
pub type O = String;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Inst {
|
||||
SwapPos (usize, usize),
|
||||
SwapLetter (char, char),
|
||||
RotateLeft (usize),
|
||||
RotateRight (usize),
|
||||
RotatePos (char),
|
||||
Reverse (usize, usize),
|
||||
Move (usize, usize)
|
||||
}
|
||||
|
||||
// const _rotations: [usize; 8] = [1,2,3,4,6,7,0,1];
|
||||
// ↓
|
||||
const _rotations: [usize; 8] = [1,1,6,2,7,3,0,4];
|
||||
|
||||
|
||||
impl Inst {
|
||||
fn from_str (i: &str) -> Self {
|
||||
let i = i.trim();
|
||||
if let Some(sfx) = i.strip_prefix("swap position ") {
|
||||
let (l, r) = sfx.split_once(" with position ").unwrap();
|
||||
Inst::SwapPos(p!(l), p!(r))
|
||||
} else if let Some(sfx) = i.strip_prefix("swap letter ") {
|
||||
let (l, r) = sfx.split_once(" with letter ").unwrap();
|
||||
Inst::SwapLetter(l.trim().chars().next().unwrap(), r.trim().chars().next().unwrap())
|
||||
} else if let Some(sfx) = i.strip_prefix("rotate left ") {
|
||||
let (l, _) = sfx.split_once(' ').unwrap();
|
||||
Inst::RotateLeft(p!(l))
|
||||
} else if let Some(sfx) = i.strip_prefix("rotate right ") {
|
||||
let (l, _) = sfx.split_once(' ').unwrap();
|
||||
Inst::RotateRight(p!(l))
|
||||
} else if let Some(sfx) = i.strip_prefix("rotate based on position of letter ") {
|
||||
Inst::RotatePos(sfx.chars().next().unwrap())
|
||||
} else if let Some(sfx) = i.strip_prefix("reverse positions ") {
|
||||
let (l, r) = sfx.split_once(" through ").unwrap();
|
||||
Inst::Reverse(p!(l), p!(r))
|
||||
} else if let Some(sfx) = i.strip_prefix("move position ") {
|
||||
let (l, r) = sfx.split_once(" to position ").unwrap();
|
||||
Inst::Move(p!(l), p!(r))
|
||||
} else {
|
||||
panic!("unknown instruction")
|
||||
}
|
||||
}
|
||||
|
||||
fn apply (self, target: &mut Vec<char>) {
|
||||
use Inst as I;
|
||||
match self {
|
||||
I::SwapPos(l, r) => target.swap(l, r),
|
||||
I::SwapLetter(l, r) => {
|
||||
let lpos = target.iter().position(|&c| c == l);
|
||||
let rpos = target.iter().position(|&c| c == r);
|
||||
if let Some(lpos) = lpos && let Some(rpos) = rpos {
|
||||
target.swap(lpos, rpos);
|
||||
}
|
||||
},
|
||||
I::RotateLeft(times) => target.rotate_left(times),
|
||||
I::RotateRight(times) => target.rotate_right(times),
|
||||
I::RotatePos(needle) => {
|
||||
let pos = target.iter().position(|&c| c == needle);
|
||||
if let Some(pos) = pos {
|
||||
let rotations = pos + 1 + if pos >= 4 { 1 } else { 0 };
|
||||
let len = target.len(); // % len is useless in my input but needed for the general correctness of the algorithm
|
||||
target.rotate_right(rotations % len);
|
||||
}
|
||||
},
|
||||
I::Reverse(from, to) => (&mut target[from..=to]).reverse(),
|
||||
I::Move(from, to) => {
|
||||
let val = target.remove(from);
|
||||
target.insert(to, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn undo (self, target: &mut Vec<char>) {
|
||||
use Inst as I;
|
||||
match self {
|
||||
I::SwapPos(l, r) => target.swap(l, r),
|
||||
I::SwapLetter(l, r) => {
|
||||
let lpos = target.iter().position(|&c| c == l);
|
||||
let rpos = target.iter().position(|&c| c == r);
|
||||
if let Some(lpos) = lpos && let Some(rpos) = rpos {
|
||||
target.swap(lpos, rpos);
|
||||
}
|
||||
},
|
||||
I::RotateLeft(times) => target.rotate_right(times),
|
||||
I::RotateRight(times) => target.rotate_left(times),
|
||||
I::RotatePos(needle) => {
|
||||
let pos = target.iter().position(|&c| c == needle);
|
||||
if let Some(pos) = pos {
|
||||
target.rotate_left(_rotations[pos]);
|
||||
}
|
||||
},
|
||||
I::Reverse(from, to) => (&mut target[from..=to]).reverse(),
|
||||
I::Move(from, to) => {
|
||||
let val = target.remove(to);
|
||||
target.insert(from, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn _parse (data: &str) -> I {
|
||||
data.trim().lines().map(Inst::from_str).collect()
|
||||
}
|
||||
|
||||
fn _silver (start: &'static str, list: I) -> O {
|
||||
let mut state = start.chars().collect_vec();
|
||||
list.into_iter().for_each(|i| i.apply(&mut state));
|
||||
state.into_iter().collect()
|
||||
}
|
||||
|
||||
fn _gold (start: &'static str, mut list: I) -> O {
|
||||
list.reverse();
|
||||
let mut state = start.chars().collect_vec();
|
||||
list.into_iter().for_each(|i| i.undo(&mut state));
|
||||
state.into_iter().collect()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
fn read () -> I {
|
||||
let data = inc!(21);
|
||||
_parse(data)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn silver () {
|
||||
let data = read();
|
||||
let ans = _silver("abcdefgh", data);
|
||||
|
||||
assert_eq!(ans, s!("bfheacgd"))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gold () {
|
||||
let data = read();
|
||||
let ans = _gold("fbgdceah", data);
|
||||
|
||||
assert_eq!(ans, s!("gcehdbfa"))
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user