advent-of-code/2022/src/bin/day05.rs

101 lines
2.8 KiB
Rust
Raw Normal View History

2022-12-05 11:35:34 +01:00
#![feature(test, slice_take)]
2022-12-05 10:02:52 +01:00
extern crate test;
2022-12-05 11:35:34 +01:00
2022-12-05 10:02:52 +01:00
use aoc2022::{boilerplate, common::*};
const DAY: usize = 5;
2022-12-05 11:15:40 +01:00
type Parsed = (Vec<Vec<u8>>, Vec<Move>);
#[derive(Debug)]
struct Move {
n: usize,
src: usize,
dst: usize,
}
2022-12-05 10:02:52 +01:00
fn parse_input(raw: &str) -> Parsed {
2022-12-05 11:15:40 +01:00
let mut lines = raw.lines();
let mut raw_stacks = Vec::new();
let stack_numbers = loop {
match lines.next() {
Some(line) if line.contains('[') => raw_stacks.push(line),
Some(line) => break line,
None => unreachable!(),
}
};
let num_stacks = (stack_numbers.trim().bytes().last().unwrap() - b'0') as usize;
let mut stacks = vec![vec![]; num_stacks];
2022-12-05 11:35:34 +01:00
for &s in raw_stacks.iter().rev() {
for (n, stack) in stacks.iter_mut().enumerate() {
2022-12-05 11:15:40 +01:00
match s.as_bytes().get(1 + 4 * n) {
Some(b' ') | None => (),
2022-12-05 11:35:34 +01:00
Some(&c) => stack.push(c),
2022-12-05 11:15:40 +01:00
}
}
}
let moves = lines
.skip(1)
2022-12-05 11:35:34 +01:00
.map(|l| match l.as_bytes() {
[_, _, _, _, _, n, _, _, _, _, _, _, src, _, _, _, _, dst] => {
Move { n: (n - b'0') as usize, src: (src - b'1') as _, dst: (dst - b'1') as _ }
}
[_, _, _, _, _, n1, n2, _, _, _, _, _, _, src, _, _, _, _, dst] => {
Move { n: ((n1 - b'0') * 10 + n2 - b'0') as _, src: (src - b'1') as _, dst: (dst - b'1') as _ }
}
_ => unreachable!("Operations can’t be repeated more than 99 times"),
2022-12-05 11:15:40 +01:00
})
.collect();
(stacks, moves)
2022-12-05 10:02:52 +01:00
}
2022-12-05 11:15:40 +01:00
fn part1((stacks, moves): &Parsed) -> String {
let mut stacks = stacks.to_owned();
for mov in moves {
for _ in 0..(mov.n) {
let e = stacks[mov.src].pop().unwrap();
stacks[mov.dst].push(e);
}
}
stacks.iter().filter_map(|s| s.last()).map(|&b| b as char).collect()
2022-12-05 10:02:52 +01:00
}
2022-12-05 11:15:40 +01:00
fn part2((stacks, moves): &Parsed) -> String {
let mut stacks = stacks.to_owned();
let mut temp = Vec::new();
for mov in moves {
// Sadly can’t drain from one into the other because the compiler doesn’t know
// src and dst are always different :feelsBadMan:
let start_index = stacks[mov.src].len() - mov.n;
temp.extend(stacks[mov.src].drain(start_index..));
for e in temp.drain(..) {
stacks[mov.dst].push(e);
}
}
stacks.iter().filter_map(|s| s.last()).map(|&b| b as char).collect()
2022-12-05 10:02:52 +01:00
}
boilerplate! {
2022-12-05 11:15:40 +01:00
TEST_INPUT ==
" [D]
[N] [C]
[Z] [M] [P]
1 2 3
move 1 from 2 to 1
move 3 from 1 to 3
move 2 from 2 to 1
move 1 from 1 to 2",
2022-12-05 10:02:52 +01:00
tests: {
2022-12-05 11:15:40 +01:00
part1: { TEST_INPUT => "CMZ" },
part2: { TEST_INPUT => "MCD" },
2022-12-05 10:02:52 +01:00
},
2022-12-05 11:15:40 +01:00
bench1 == "QMBMJDFTD",
bench2 == "NBTVTJNFJ",
bench_parse: check_input => 504,
}
#[cfg(test)]
fn check_input((_, moves): &Parsed) -> usize {
moves.len()
2022-12-05 10:02:52 +01:00
}