diff options
Diffstat (limited to '2022/src/day05.rs')
-rw-r--r-- | 2022/src/day05.rs | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/2022/src/day05.rs b/2022/src/day05.rs new file mode 100644 index 0000000..f45cd0a --- /dev/null +++ b/2022/src/day05.rs @@ -0,0 +1,145 @@ +//! Day 5: Supply Stacks + +extern crate bumpalo; + +mod utils; + +use bumpalo::Bump; +use std::cell::Cell; +use utils::{parse_num, parse_static, read_input}; + +/// Base type for a crate +#[derive(Debug, Clone)] +struct Crate<'a> { + letter: char, + below: Cell<Option<&'a Crate<'a>>>, +} + +impl Default for Crate<'_> { + fn default() -> Self { + Crate { + letter: ' ', + below: None.into(), + } + } +} + +/// A move the crane may make +#[derive(Debug, Clone, Copy)] +struct Move { + reps: usize, + from: usize, + to: usize, +} +type Tops<'arena> = Vec<Option<&'arena Crate<'arena>>>; + +fn main() { + let input = read_input(); + + { + let arena = Bump::new(); + let mut tops = construct_piles(&input, &arena); + for mv in parse_moves(&input) { + perform_move_9000(&mut tops, mv); + } + + println!("Part 1: {}", top_letters(tops)); + } + + { + let arena = Bump::new(); + let mut tops = construct_piles(&input, &arena); + for mv in parse_moves(&input) { + perform_move_9001(&mut tops, mv); + } + + println!("Part 2: {}", top_letters(tops)); + } +} + +/// Get the message / the top letters of each stack +fn top_letters(tops: Tops<'_>) -> String { + tops.iter().map(|x| x.as_ref().unwrap().letter).collect() +} + +/// Perform a move for part 1 +fn perform_move_9000(tops: &mut Tops<'_>, mv: Move) { + for _ in 0..mv.reps { + let from = tops[mv.from].take().unwrap(); + let to = tops[mv.to].take(); + + tops[mv.from] = from.below.replace(to); + tops[mv.to] = Some(from); + } +} + +/// Perform a move for part 2 +fn perform_move_9001(tops: &mut Tops<'_>, mv: Move) { + let pickup_top = tops[mv.from].take().unwrap(); + + let mut pickup_bot = pickup_top; + for _ in 1..mv.reps { + pickup_bot = pickup_bot.below.get().as_ref().unwrap(); + } + + let to = tops[mv.to].take(); + + tops[mv.from] = pickup_bot.below.replace(to); + tops[mv.to] = Some(pickup_top); +} + +// Annoying parsing code! + +fn construct_piles<'a>(input: &str, arena: &'a Bump) -> Tops<'a> { + let mut piles = Vec::new(); + for layer_iter in input + .lines() + .take_while(|x| x.chars().find(|x| *x != ' ').unwrap() == '[') + .map(|x| x.chars().skip(1).step_by(4)) + { + for (stack, chr) in layer_iter.enumerate() { + if piles.len() < stack + 1 { + piles.resize(stack + 1, None); + } + + if chr != ' ' { + let val = &*arena.alloc(Crate { + letter: chr, + below: None.into(), + }); + if piles[stack].is_none() { + piles[stack] = Some(val); + } else { + let mut top = *piles[stack].as_ref().unwrap(); + while let Some(below) = top.below.get() { + top = below; + } + + top.below.set(Some(val)); + } + } + } + } + + piles +} + +fn parse_moves(input: &str) -> impl Iterator<Item = Move> + '_ { + input + .lines() + .skip_while(|line| !line.starts_with('m')) + .map(|line| { + let line = parse_static("move ", line); + let (reps, line) = parse_num(line); + let line = parse_static(" from ", line); + let (from, line) = parse_num::<usize>(line); + let line = parse_static(" to ", line); + let (to, _) = parse_num::<usize>(line); + + Move { + reps, + from: from - 1, + to: to - 1, + } + }) +} |