Untitled
unknown
rust
2 years ago
4.6 kB
10
Indexable
use itertools::Itertools; use std::{collections::VecDeque, fs, process::exit}; #[derive(Debug)] struct Instruction { from: usize, to: usize, quantity: usize, } impl From<&str> for Instruction { fn from(line: &str) -> Self { let (quantity, from, to) = line .split(" ") .skip(1) .step_by(2) .map(|x| x.parse::<usize>().expect("could not parse instruction")) .collect_tuple::<(usize, usize, usize)>() .expect("could not parse instruction line"); Instruction { from: from - 1, to: to - 1, quantity, } } } #[derive(Debug)] struct Ship { crates: Vec<VecDeque<char>>, } impl Ship { fn new(size: usize) -> Self { Self { crates: vec![VecDeque::default(); size], } } fn push_element(&mut self, element: char, to_idx: usize) { self.crates .get_mut(to_idx) .expect("attempting to index a crate that does not exist") .push_front(element); } fn move_elements<Crane: CrateMover>( &mut self, num_elements: usize, from_idx: usize, to_idx: usize, ) { let cargo_to_move: Vec<char> = self .crates .get_mut(from_idx) .expect("referenced non-existent crate") .drain(0..num_elements) .collect(); Crane::move_crate(self, cargo_to_move, to_idx) } fn top_elements(&self) -> Vec<char> { self.crates .iter() .filter_map(|stack| stack.front()) .map(|element| *element) .collect() } } impl From<&str> for Ship { fn from(input: &str) -> Self { let mut input = input.lines().rev(); let num_crates = input .next() .expect("Missing stack count line") .split(" ") .last() .expect("Unable to parse stack count line") .parse::<usize>() .expect("Unable to parse stack count line"); let mut ship = Ship::new(num_crates); fn parse_crate_line(line: &str) -> Vec<char> { line.chars().skip(1).step_by(4).collect() } input .map(parse_crate_line) .for_each(|crate_line: Vec<char>| { let important_elements = crate_line .into_iter() .enumerate() .filter(|(_, c)| !c.is_whitespace()); for (idx, element) in important_elements { ship.push_element(element, idx); } }); ship } } fn main() { let contents = match fs::read_to_string("input.txt") { Ok(content) => content, Err(err) => { println!("could not read file\nerr: {err}"); exit(1); } }; println!("part 1: {}", part_one(&contents)); println!("part two: {}", part_two(&contents)); } fn part_one(input: &str) -> String { let (mut ship, instructions) = parse_initial_conf(input); for Instruction { from, to, quantity } in instructions { ship.move_elements::<Crane9000>(quantity, from, to); } ship.top_elements().into_iter().collect::<String>() } fn part_two(input: &str) -> String { let (mut ship, instructions) = parse_initial_conf(input); for Instruction { from, to, quantity } in instructions { ship.move_elements::<Crane9001>(quantity, from, to); } ship.top_elements().into_iter().collect::<String>() } fn parse_initial_conf(input: &str) -> (Ship, Vec<Instruction>) { let [ship_config, instructions]: [&str; 2] = input .split("\n\n") .collect::<Vec<&str>>() .try_into() .expect("unable to parse input"); let ship = Ship::from(ship_config); let instructions = instructions .lines() .map(Instruction::from) .collect::<Vec<Instruction>>(); (ship, instructions) } struct Crane9000; struct Crane9001; trait CrateMover { fn move_crate(ship: &mut Ship, cargo: Vec<char>, to_idx: usize); } impl CrateMover for Crane9000 { fn move_crate(ship: &mut Ship, cargo: Vec<char>, to_idx: usize) { for element in cargo { ship.push_element(element, to_idx); } } } impl CrateMover for Crane9001 { fn move_crate(ship: &mut Ship, cargo: Vec<char>, to_idx: usize) { for element in cargo.into_iter().rev() { ship.push_element(element, to_idx); } } }
Editor is loading...