aboutsummaryrefslogtreecommitdiff
path: root/2022/src/day05.rs
diff options
context:
space:
mode:
Diffstat (limited to '2022/src/day05.rs')
-rw-r--r--2022/src/day05.rs145
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,
+ }
+ })
+}