Untitled
unknown
rust
2 years ago
4.6 kB
13
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...