You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

155 lines
2.9 KiB
Rust

static INPUT: &str = include_str!("inputs/day5.txt");
type CrateID = char;
#[derive(Debug)]
struct Stacks(Vec<Vec<CrateID>>);
impl Stacks {
fn apply_move_part_1(&mut self, mv: &Move) {
let from = mv.from - 1;
let to = mv.to - 1;
for _ in 0..mv.count {
let c = self.0[from].pop().unwrap();
self.0[to].push(c)
}
}
fn apply_move_part_2(&mut self, mv: &Move) {
let from = mv.from - 1;
let to = mv.to - 1;
// SAFETY: should be safe, borrowing from disjoint sub-vectors and
// not modifying the length of the primary vector. Technically it
// is possible that this could alias if to and from are the same,
// but even if that happened this should be safe (although the
// answer given would be incorrect)
unsafe {
let from: &'static mut Vec<_> =
core::mem::transmute(&mut self.0[from]);
let new_len = from.len() - mv.count;
let picked_up = &from[new_len..];
self.0[to].extend_from_slice(picked_up);
from.truncate(new_len);
}
}
}
fn parse_stacks(s: &str) -> Stacks {
let mut lines = s.split('\n').filter(|s| !s.is_empty()).map(|line| {
let mut chars = line.chars();
core::iter::from_fn(move || {
match chars.next() {
None => return None,
Some(_) => (),
};
let id = chars.next().unwrap();
chars.next();
chars.next();
if id == ' ' {
return Some(None);
}
Some(Some(id))
})
});
let mut crates = Vec::new();
let first_line = lines.next().unwrap();
for id in first_line {
let mut stack = Vec::new();
if let Some(id) = id {
stack.push(id);
}
crates.push(stack);
}
for ids in lines {
for (idx, id) in ids.enumerate() {
if let Some(id) = id {
crates[idx].push(id);
}
}
}
for stack in &mut crates {
stack.pop();
stack.reverse();
}
Stacks(crates)
}
#[derive(Debug)]
struct Move {
count: usize,
from: usize,
to: usize,
}
fn parse_moves(s: &str) -> impl Iterator<Item = Move> + '_ {
s.split('\n').filter(|s| !s.is_empty()).map(|line| {
let mut words = line.split(' ');
let count = {
words.next();
words.next().unwrap()
};
let from = {
words.next();
words.next().unwrap()
};
let to = {
words.next();
words.next().unwrap()
};
Move {
count: count.parse().unwrap(),
from: from.parse().unwrap(),
to: to.parse().unwrap(),
}
})
}
fn parse(s: &str) -> (Stacks, impl Iterator<Item = Move> + '_) {
let mut parts = s.split("\n\n");
let crates_str = parts.next().unwrap();
let stacks = parse_stacks(crates_str);
let moves_str = parts.next().unwrap();
let moves = parse_moves(moves_str);
(stacks, moves)
}
pub fn part1() {
let (mut stacks, moves) = parse(INPUT);
for mv in moves {
stacks.apply_move_part_1(&mv);
}
for stack in &stacks.0 {
print!("{}", stack.last().unwrap());
}
println!();
}
pub fn part2() {
let (mut stacks, moves) = parse(INPUT);
for mv in moves {
stacks.apply_move_part_2(&mv);
}
for stack in &stacks.0 {
print!("{}", stack.last().unwrap());
}
println!();
}