From 666b11bc77f17d6d2b5a466c56ea7710bb9134fd Mon Sep 17 00:00:00 2001 From: Shivesh Mandalia Date: Wed, 21 Dec 2022 18:17:44 +0000 Subject: complete day 5 --- day05b/src/main.rs | 268 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 268 insertions(+) create mode 100644 day05b/src/main.rs (limited to 'day05b/src') diff --git a/day05b/src/main.rs b/day05b/src/main.rs new file mode 100644 index 0000000..4018b83 --- /dev/null +++ b/day05b/src/main.rs @@ -0,0 +1,268 @@ +/// --- Part Two --- +/// +/// As you watch the crane operator expertly rearrange the crates, you notice the process isn't +/// following your prediction. +/// +/// Some mud was covering the writing on the side of the crane, and you quickly wipe it away. The +/// crane isn't a CrateMover 9000 - it's a CrateMover 9001. +/// +/// The CrateMover 9001 is notable for many new and exciting features: air conditioning, leather +/// seats, an extra cup holder, and the ability to pick up and move multiple crates at once. +/// +/// Again considering the example above, the crates begin in the same configuration: +/// +/// ``` +/// [D] +/// [N] [C] +/// [Z] [M] [P] +/// 1 2 3 +/// ``` +/// +/// Moving a single crate from stack 2 to stack 1 behaves the same as before: +/// +/// ``` +/// [D] +/// [N] [C] +/// [Z] [M] [P] +/// 1 2 3 +/// ``` +/// +/// However, the action of moving three crates from stack 1 to stack 3 means that those three moved +/// crates stay in the same order, resulting in this new configuration: +/// +/// ``` +/// [D] +/// [N] +/// [C] [Z] +/// [M] [P] +/// 1 2 3 +/// ``` +/// +/// Next, as both crates are moved from stack 2 to stack 1, they retain their order as well: +/// +/// ``` +/// [D] +/// [N] +/// [C] [Z] +/// [M] [P] +/// 1 2 3 +/// ``` +/// +/// Finally, a single crate is still moved from stack 1 to stack 2, but now it's crate C that gets moved: +/// +/// ``` +/// [D] +/// [N] +/// [Z] +/// [M] [C] [P] +/// 1 2 3 +/// ``` +/// +/// In this example, the CrateMover 9001 has put the crates in a totally different order: MCD. +/// +/// Before the rearrangement process finishes, update your simulation so that the Elves know where +/// they should stand to be ready to unload the final supplies. After the rearrangement procedure +/// completes, what crate ends up on top of each stack? +use clap::Parser; +use itertools::Itertools; +use nom::branch::alt; +use nom::bytes::complete::tag; +use nom::character::complete::{alpha1, digit1, multispace1}; +use nom::combinator::{map, opt, peek}; +use nom::error::{ErrorKind as NomErrorKind, ParseError}; +use nom::multi::{many1, many1_count}; +use nom::sequence::{delimited, preceded, terminated}; +use nom::IResult; + +use std::fs::File; +use std::io::prelude::*; +use std::io::BufReader; +use std::iter::*; +use std::path::PathBuf; + +pub type Input<'a> = &'a str; +pub type Result<'a, T> = IResult, T, Error>>; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum ErrorKind { + Nom(NomErrorKind), + Context(&'static str), + Custom(String), +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Error { + pub errors: Vec<(I, ErrorKind)>, +} + +impl ParseError for Error { + fn from_error_kind(input: I, kind: NomErrorKind) -> Self { + let errors = vec![(input, ErrorKind::Nom(kind))]; + Self { errors } + } + + fn append(input: I, kind: NomErrorKind, mut other: Self) -> Self { + other.errors.push((input, ErrorKind::Nom(kind))); + other + } +} + +const FILEPATH: &'static str = "examples/input.txt"; + +#[derive(Parser, Debug)] +#[clap(author, version, about, long_about = None)] +struct Cli { + #[clap(short, long, default_value = FILEPATH)] + file: PathBuf, +} + +#[derive(Debug, Clone)] +struct Supplies(Vec>); + +#[derive(Debug, Clone)] +struct Order { + from: usize, + to: usize, + amount: usize, +} + +#[derive(Debug, Clone)] +enum LineKind { + Axis(usize), + Crates(Vec), +} + +fn parse_digit(input: &str) -> Result { + map(preceded(multispace1, digit1), |s: &str| { + s.chars().next().unwrap() + })(input) +} + +fn parse_crate(input: &str) -> Result { + map(delimited(tag("["), alpha1, tag("]")), |s: &str| { + s.chars().next().unwrap() + })(input) +} + +fn parse_crate_or_empty(input: &str) -> Result { + terminated(alt((map(tag(" "), |_| ' '), parse_crate)), opt(tag(" ")))(input) +} + +fn parse_line(input: &str) -> Result { + let res = peek(parse_digit)(input); + if res.is_ok() { + map(many1_count(parse_digit), |len| LineKind::Axis(len))(input) + } else { + map(many1(parse_crate_or_empty), |v| LineKind::Crates(v))(input) + } +} + +impl Supplies { + fn new() -> Self { + Self(Vec::>::new()) + } + + fn idx_to_internal(idx: usize) -> usize { + idx - 1 + } + + fn initialize(&mut self, input: Vec) { + let axis = &input[input.len() - 1]; + let LineKind::Axis(len) = axis else { + panic!(); + }; + self.resize(*len); + + let _ = input + .into_iter() + .rev() + .skip(1) + .map(|x| match x { + LineKind::Crates(v) => v, + _ => panic!(), + }) + .map(|vc| { + vc.into_iter() + .zip(1usize..) + .filter(|(c, _)| *c != ' ') + .collect_vec() + }) + .flatten() + .scan(self, |state, (c, idx)| { + state.push(idx, c); + Some(()) + }) + .last(); + } + + fn pop(&mut self, idx: usize) -> char { + self.0[Self::idx_to_internal(idx)].pop().unwrap() + } + + fn peek(&self, idx: usize) -> char { + self.0[Self::idx_to_internal(idx)][self.0[Self::idx_to_internal(idx)].len() - 1] + } + + fn push(&mut self, idx: usize, letter: char) { + self.0[Self::idx_to_internal(idx)].push(letter) + } + + fn resize(&mut self, len: usize) { + self.0.resize(len, Vec::::new()) + } + + fn top_chars(&self) -> String { + (0..self.0.len()) + .map(|idx| self.peek(idx + 1).to_string()) + .join("") + } + + fn transfer(&mut self, order: Order) { + let popped = (0..order.amount) + .into_iter() + .map(|_| self.pop(order.from)) + .collect_vec(); + for c in popped.into_iter().rev() { + self.push(order.to, c); + } + } +} + +fn main() { + let args = Cli::parse(); + + let file = File::open(&args.file).unwrap(); + let reader = BufReader::new(file); + + let init = reader + .lines() + .map(|l| l.unwrap()) + .take_while(|l| !l.is_empty()) + .map(|l| parse_line(l.as_str()).unwrap().1) + .collect_vec(); + + let mut supplies = Supplies::new(); + supplies.initialize(init); + + let file = File::open(&args.file).unwrap(); + let reader = BufReader::new(file); + let _ = reader + .lines() + .map(|l| l.unwrap()) + .skip_while(|l| !l.contains("move")) + .map(|l| { + let sp = l.split_whitespace().collect_vec(); + Order { + from: sp[3].parse::().unwrap(), + to: sp[5].parse::().unwrap(), + amount: sp[1].parse::().unwrap(), + } + }) + .scan(&mut supplies, |state, order| { + state.transfer(order); + Some(()) + }) + .last(); + + println!("{}", supplies.top_chars()); +} -- cgit v1.2.3