From 3b9a3eed0c458a8cd54c2600fd3cd855bb42e7c6 Mon Sep 17 00:00:00 2001 From: Joseph Montanaro Date: Mon, 5 Dec 2022 20:12:57 -0800 Subject: [PATCH] it's ugly but it works --- 2021/src/day18.rs | 12 ++--- 2022/Cargo.toml | 5 ++ 2022/src/day5.rs | 126 ++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 114 insertions(+), 29 deletions(-) diff --git a/2021/src/day18.rs b/2021/src/day18.rs index 4853cb2..ba867d1 100644 --- a/2021/src/day18.rs +++ b/2021/src/day18.rs @@ -91,14 +91,10 @@ fn explode(node: &mut Node, depth: usize) -> Option<(u8, u8)> { if let Leaf(_) = node {return None;} if depth >= 4 { - let (left, right) = node.unwrap_branch(); - match (left, right) { - (Leaf(v1), Leaf(v2)) => { - let result = (*v1, *v2); - *node = Leaf(0); - return Some(result); - }, - _ => (), + if let (Leaf(v1), Leaf(v2)) = node.unwrap_branch() { + let result = (*v1, *v2); + *node = Leaf(0); + return Some(result); } } diff --git a/2022/Cargo.toml b/2022/Cargo.toml index 60f9732..9d4c100 100644 --- a/2022/Cargo.toml +++ b/2022/Cargo.toml @@ -23,6 +23,11 @@ path = "src/day3.rs" name = "day4" path = "src/day4.rs" +[[bin]] +name = "day5" +path = "src/day5.rs" + + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] diff --git a/2022/src/day5.rs b/2022/src/day5.rs index 313e8ff..fe64182 100644 --- a/2022/src/day5.rs +++ b/2022/src/day5.rs @@ -1,29 +1,113 @@ -const DATA: &'static str = " - [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 -"; +use core::num::ParseIntError; -struct State { - stacks: Vec>, +const DATA: &'static str = include_str!("../data/day5.txt"); +// const DATA: &'static str = " +// [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 +// "; + + +enum BadLine { + NotEnoughWords, + ParseError(ParseIntError), } -impl std::str::FromStr for State { - fn from_str(data: &str) -> State { - let lines: Vec<&str> = data.lines().collect(); - let mut stacks = Vec::new(Vec::new()); - // skip the first row, because it's just the stack numbers - for row in lines.rev().skip(1) { - for (i, ident) in row.split(' ') { - let ident = ident.trim_matches(|c| c == '[' || c == ']'); + +#[derive(Debug)] +struct State { + stacks: [Vec; 9], +} + +impl State { + fn process(&mut self, op: &Instruction) { + for _ in 0..(op.count) { + let item = self.stacks[op.src as usize - 1].pop().unwrap(); + self.stacks[op.dst as usize - 1].push(item); + } + } + + fn process_inorder(&mut self, op: &Instruction) { + let src_stack = &mut self.stacks[op.src as usize - 1]; + let split_idx = src_stack.len() - op.count as usize; + let mut substack = src_stack.split_off(split_idx); + self.stacks[op.dst as usize - 1].append(&mut substack); + } + + fn get_tops(&self) -> String { + let mut res = String::with_capacity(9); + for stack in &self.stacks { + res.push(*stack.last().unwrap()); + } + res + } +} + + +#[derive(Debug)] +struct Instruction { + count: u32, + src: u32, + dst: u32, +} + + +fn parse_map(map: &str) -> State { + let rows: Vec<&str> = map.lines().collect(); + let mut stacks: [Vec; 9] = Default::default(); + // skip the first row, because it's just the stack numbers + for row in rows.iter().rev().skip(1) { + for (col_num, c) in row.chars().enumerate() { + if c.is_ascii_uppercase() { + let stack_idx = (col_num - 1) / 4; + stacks[stack_idx].push(c); } } } + + State { stacks } +} + + +fn parse_instruction(data: &str) -> Result { + let mut words = data.split(' '); + Ok(Instruction { + count: words.nth(1).ok_or(BadLine::NotEnoughWords)?.parse().map_err(|e| BadLine::ParseError(e))?, + src: words.nth(1).ok_or(BadLine::NotEnoughWords)?.parse().map_err(|e| BadLine::ParseError(e))?, + dst: words.nth(1).ok_or(BadLine::NotEnoughWords)?.parse().map_err(|e| BadLine::ParseError(e))?, + }) +} + + +fn main() -> Result<(), String> { + let mut splat = DATA.trim_end().split("\n\n"); + let map = splat.next().unwrap(); + let instruction_lines = splat.next().unwrap(); + let mut state = parse_map(map); + + let instructions: Vec = instruction_lines.lines() + .map(|line| parse_instruction(line).map_err(|_e| format!("Bad line: {line}"))) + .collect::, String>>()?; + + for i in &instructions { + state.process(i); + } + + println!("Part 1: {}", state.get_tops()); + + let mut state2 = parse_map(map); + for i in &instructions { + state2.process_inorder(i); + } + + println!("Part 2: {}", state2.get_tops()); + + Ok(()) }