Compare commits

..
4 Commits
Author SHA1 Message Date
YK 1670ffc8d7 add macro for .next().unwrap() 2024-12-01 20:35:18 +03:00
YK 9f353660f1 solution: day 21 2024-11-27 17:03:06 +03:00
YK 9c0653f39e add macro for .parse().unwrap() 2024-11-27 17:02:56 +03:00
YK ce521e996a solution: day 20 2024-11-27 12:37:41 +03:00
4 changed files with 240 additions and 2 deletions

No files matched your search

+2 -2
View File
@@ -17,8 +17,8 @@ pub mod d16;
pub mod d17; 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;
+74
View File
@@ -0,0 +1,74 @@
#![allow(unused_imports)]
use std::ops::RangeInclusive;
use crate::prelude::*;
pub type I = Vec<RangeInclusive<u64>>;
pub type O = u64;
fn _parse (data: &str) -> I {
data.trim().lines().map(|e| e.trim().split_once('-').map(|(a, b)| a.parse().unwrap()..=b.parse().unwrap()).unwrap()).collect()
}
fn _silver (mut data: I) -> O {
data.sort_by_key(|d| *d.start());
let mut start = data[0].end() + 1;
for d in &data[1..] {
if *d.start() <= start {
start = start.max(d.end() + 1);
continue;
}
return start;
}
Default::default()
}
fn _gold (mut data: I) -> O {
data.sort_by_key(|d| *d.start());
let mut start = data[0].end() + 1;
let mut gaps = 0;
for d in &data[1..] {
if *d.start() <= start {
start = start.max(d.end() + 1);
continue;
}
let l = d.start() - start;
gaps += l;
start = d.end() + 1;
}
// doesn't matter in my input, but for a general case where there's a gap between last
// blocked ip and last possible ip will matter. check is here to ensure it won't overflow
if start <= u32::MAX as u64 {
gaps += u32::MAX as u64 - start;
}
gaps
}
#[cfg(test)]
mod test {
use super::*;
fn read () -> I {
let data = inc!(20);
_parse(data)
}
#[test]
fn silver () {
let data = read();
let ans = _silver(data);
assert_eq!(ans, 17348574)
}
#[test]
fn gold () {
let data = read();
let ans = _gold(data);
assert_eq!(ans, 104)
}
}
+151
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"))
}
}
+13
View File
@@ -9,3 +9,16 @@ pub macro s {
format!("{}", $s) format!("{}", $s)
} }
} }
pub macro p {
($s: expr) => {
$s.parse().unwrap()
}
}
pub macro n {
($s: expr) => {
$s.next().unwrap()
}
}