summaryrefslogtreecommitdiff
path: root/2022/src/bin/day_5.rs
diff options
context:
space:
mode:
Diffstat (limited to '2022/src/bin/day_5.rs')
-rw-r--r--2022/src/bin/day_5.rs147
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)
+ }
+}