1
0
Fork 0
advent-of-code/src/bin/p05.rs

218 lines
5.0 KiB
Rust

#![feature(iterator_try_collect)]
use std::fs;
use std::str;
use std::str::FromStr;
// not that type of crate
#[derive(Debug, Copy, Clone)]
struct Crate(char);
impl FromStr for Crate {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if let Some(c) = s.trim_matches(&['[', ']'] as &[_]).chars().next() {
Ok(Crate(c))
} else {
Err("Expected a character")
}
}
}
#[derive(Debug)]
struct CrateStack(Vec<Crate>);
impl CrateStack {
fn new() -> Self {
Self(Vec::new())
}
fn push(&mut self, cr: Crate) {
self.0.push(cr)
}
fn pop(&mut self) -> Option<Crate> {
self.0.pop()
}
}
impl FromStr for CrateStack {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(CrateStack(
s.lines().flat_map(|l| l.parse::<Crate>()).collect(),
))
}
}
#[derive(Debug)]
struct Dock(Vec<CrateStack>);
trait Crane {
fn run_directive(dock: &mut Dock, directive: &MoveDirective) -> bool;
}
impl Dock {
fn tops(&self) -> impl Iterator<Item = Option<&Crate>> {
self.0.iter().map(|s| s.0.iter().last())
}
}
struct CrateMover9000;
impl Crane for CrateMover9000 {
fn run_directive(dock: &mut Dock, directive: &MoveDirective) -> bool {
if directive.source >= dock.0.len() {
return false;
}
if directive.dest >= dock.0.len() {
return false;
}
for _ in 0..directive.number {
if let Some(s) = dock.0[directive.source].pop() {
dock.0[directive.dest].push(s)
}
}
true
}
}
struct CrateMover9001;
impl Crane for CrateMover9001 {
fn run_directive(dock: &mut Dock, directive: &MoveDirective) -> bool {
if directive.source >= dock.0.len() {
return false;
}
if directive.dest >= dock.0.len() {
return false;
}
let source_vec = &mut dock.0[directive.source].0;
let drained: Vec<Crate> = source_vec
.drain((source_vec.len() - usize::try_from(directive.number).unwrap())..)
.collect();
dock.0[directive.dest].0.extend(drained);
true
}
}
impl FromStr for Dock {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let rows: Vec<Vec<Option<Crate>>> = s
.lines()
.rev()
.skip(1)
.map(|l| {
l.as_bytes()
.chunks(4)
.map(|c| str::from_utf8(c).unwrap().trim().parse::<Crate>().ok())
.collect()
})
.collect();
let mut result = Vec::<CrateStack>::new();
for row in rows {
while row.len() > result.len() {
result.push(CrateStack::new())
}
for i in 0..row.len() {
if let Some(r) = row[i] {
result[i].push(r);
}
}
}
Ok(Dock(result))
}
}
#[derive(Debug)]
struct MoveDirective {
number: u32,
source: usize,
dest: usize,
}
#[derive(Debug, Clone)]
struct MoveError;
impl FromStr for MoveDirective {
type Err = MoveError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let (count, movement_str) = s
.trim_start_matches("move ")
.split_once(" from ")
.ok_or(MoveError)?;
let (first, second) = movement_str.split_once(" to ").ok_or(MoveError)?;
let source: usize = first.parse().map_err(|_| MoveError)?;
let dest: usize = second.parse().map_err(|_| MoveError)?;
Ok(MoveDirective {
number: count.parse().map_err(|_| MoveError)?,
source: source - 1,
dest: dest - 1,
})
}
}
fn main() {
let filename = "etc/p05.txt";
let string = fs::read_to_string(filename).expect("Can't open file");
let mut split = string.split("\n\n");
let dock: Dock = split
.next()
.expect("first section")
.parse::<Dock>()
.expect("can't parse dock");
let moves: Vec<MoveDirective> = split
.next()
.expect("Can't find moves")
.lines()
.map(|l| l.parse::<MoveDirective>().expect("Can't parse move"))
.collect();
println!("PART ONE ---------------");
part1(dock, &moves);
let dock2: Dock = string
.split("\n\n")
.next()
.expect("first section")
.parse::<Dock>()
.expect("can't parse dock");
println!("\n PART TWO ---------------");
part2(dock2, &moves);
}
fn part1(mut dock: Dock, moves: &[MoveDirective]) {
for m in moves {
CrateMover9000::run_directive(&mut dock, m);
}
dbg!(dock.tops().flatten().map(|c| c.0).collect::<String>());
}
fn part2(mut dock: Dock, moves: &[MoveDirective]) {
for m in moves {
CrateMover9001::run_directive(&mut dock, m);
}
dbg!(dock.tops().flatten().map(|c| c.0).collect::<String>());
}