solution: day 21

This commit is contained in:
YK 2024-11-27 17:03:06 +03:00
parent 9c0653f39e
commit 9f353660f1
2 changed files with 152 additions and 1 deletions

View File

@ -18,7 +18,7 @@ pub mod d17;
pub mod d18; pub mod d18;
pub mod d19; pub mod d19;
pub mod d20; pub mod d20;
// pub mod d21; pub mod d21;
// pub mod d22; // pub mod d22;
// pub mod d23; // pub mod d23;
// pub mod d24; // pub mod d24;

151
src/days/d21.rs Normal file
View 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"))
}
}