diff options
author | Justin Wernick <justin@worthe-it.co.za> | 2022-12-05 19:17:38 +0200 |
---|---|---|
committer | Justin Wernick <justin@worthe-it.co.za> | 2022-12-05 19:17:38 +0200 |
commit | ce2b10e9ba524205f127d3387e3ec026bccc2f8a (patch) | |
tree | 7353b25fd667527fc09836ef68f4653044c718ea /2022/src | |
parent | 8374ef5bc9d23c35b23ff1c9a9ba5f096b150921 (diff) |
Day 5
Diffstat (limited to '2022/src')
-rw-r--r-- | 2022/src/bin/day_5.rs | 147 |
1 files changed, 147 insertions, 0 deletions
diff --git a/2022/src/bin/day_5.rs b/2022/src/bin/day_5.rs new file mode 100644 index 0000000..f06012c --- /dev/null +++ b/2022/src/bin/day_5.rs @@ -0,0 +1,147 @@ +use nom::{ + branch::alt, + bytes::complete::tag, + character::complete::{ + anychar, char as nom_char, line_ending, not_line_ending, u32 as nom_u32, + }, + combinator::map, + multi::separated_list1, + sequence::tuple, + IResult, +}; +use std::fs; + +fn main() -> Result<(), Box<dyn std::error::Error>> { + let input = fs::read_to_string("inputs/day_5.txt")?; + let state = CraneState::parser(&input).unwrap().1; + + let mut state_part_1 = state.clone(); + while !state_part_1.done() { + state_part_1.process_next_instruction(false); + } + dbg!(state_part_1.read_top_row()); + + let mut state_part_2 = state.clone(); + while !state_part_2.done() { + state_part_2.process_next_instruction(true); + } + dbg!(state_part_2.read_top_row()); + + Ok(()) +} + +#[derive(Debug, PartialEq, Eq, Clone)] +struct CraneState { + towers: Vec<Tower>, + instructions: Vec<Instruction>, +} + +#[derive(Debug, Default, PartialEq, Eq, Clone)] +struct Tower { + crates: Vec<char>, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +struct Instruction { + number: usize, + src: usize, + dest: usize, +} + +impl CraneState { + fn parser(input: &str) -> IResult<&str, CraneState> { + let single_crate = alt(( + map(tuple((tag("["), anychar, tag("]"))), |(_, c, _)| Some(c)), + map(tag(" "), |_| None), + )); + let crate_row = separated_list1(nom_char(' '), single_crate); + + map( + tuple(( + separated_list1(line_ending, crate_row), + line_ending, + not_line_ending, + line_ending, + line_ending, + separated_list1(line_ending, Instruction::parser), + )), + |(crate_rows, _, _, _, _, mut instructions)| { + let mut towers = Vec::new(); + for row in &crate_rows { + for (i, c) in row + .iter() + .enumerate() + .filter_map(|(i, c)| c.map(|some_c| (i, some_c))) + { + while i >= towers.len() { + towers.push(Tower::default()); + } + towers[i].crates.push(c); + } + } + for tower in &mut towers { + tower.crates.reverse(); + } + + instructions.reverse(); + CraneState { + towers, + instructions, + } + }, + )(input) + } + + fn process_next_instruction(&mut self, maintain_order: bool) { + let Some(instruction) = self.instructions.pop() else { + return + }; + let mut to_move = Vec::new(); + for _ in 0..instruction.number { + let Some(crate_to_move) = self.towers[instruction.src].crates.pop() else { + panic!("Invalid puzzle input: failed to get crate"); + }; + to_move.push(crate_to_move); + } + if maintain_order { + to_move.reverse(); + } + for crate_to_move in to_move { + self.towers[instruction.dest].crates.push(crate_to_move); + } + } + + fn done(&self) -> bool { + self.instructions.len() == 0 + } + + fn read_top_row(&self) -> String { + let mut res = String::new(); + for tower in &self.towers { + if let Some(top) = tower.crates.last() { + res.push(*top); + } + } + res + } +} + +impl Instruction { + fn parser(input: &str) -> IResult<&str, Instruction> { + map( + tuple(( + tag("move "), + nom_u32, + tag(" from "), + nom_u32, + tag(" to "), + nom_u32, + )), + |(_, number, _, src, _, dest)| Instruction { + number: number as usize, + src: (src - 1) as usize, + dest: (dest - 1) as usize, + }, + )(input) + } +} |