day05 finished

This commit is contained in:
Ruediger Ludwig 2023-02-01 21:48:01 +01:00
parent 01f6afed9e
commit 8e4face21e
4 changed files with 780 additions and 1 deletions

9
data/day05/example01.txt Normal file
View file

@ -0,0 +1,9 @@
[D]
[N] [C]
[Z] [M] [P]
1 2 3
move 1 from 2 to 1
move 3 from 1 to 3
move 2 from 2 to 1
move 1 from 1 to 2

515
data/day05/input.txt Normal file
View file

@ -0,0 +1,515 @@
[G] [W] [Q]
[Z] [Q] [M] [J] [F]
[V] [V] [S] [F] [N] [R]
[T] [F] [C] [H] [F] [W] [P]
[B] [L] [L] [J] [C] [V] [D] [V]
[J] [V] [F] [N] [T] [T] [C] [Z] [W]
[G] [R] [Q] [H] [Q] [W] [Z] [G] [B]
[R] [J] [S] [Z] [R] [S] [D] [L] [J]
1 2 3 4 5 6 7 8 9
move 6 from 5 to 7
move 2 from 9 to 1
move 4 from 8 to 6
move 1 from 8 to 1
move 2 from 9 to 1
move 1 from 6 to 1
move 13 from 7 to 8
move 1 from 2 to 8
move 9 from 1 to 5
move 1 from 3 to 8
move 3 from 6 to 7
move 4 from 4 to 1
move 11 from 5 to 6
move 6 from 6 to 9
move 3 from 4 to 2
move 7 from 8 to 6
move 1 from 7 to 5
move 1 from 4 to 3
move 7 from 1 to 5
move 2 from 2 to 7
move 4 from 9 to 6
move 1 from 3 to 6
move 1 from 1 to 9
move 1 from 3 to 6
move 1 from 5 to 8
move 4 from 6 to 7
move 3 from 8 to 7
move 7 from 5 to 7
move 1 from 3 to 1
move 1 from 2 to 6
move 14 from 6 to 5
move 2 from 5 to 2
move 3 from 9 to 2
move 6 from 2 to 9
move 7 from 8 to 6
move 7 from 7 to 3
move 2 from 8 to 7
move 6 from 3 to 7
move 17 from 7 to 1
move 1 from 3 to 1
move 1 from 2 to 5
move 4 from 5 to 6
move 17 from 6 to 9
move 7 from 9 to 4
move 1 from 2 to 7
move 2 from 5 to 4
move 3 from 7 to 8
move 7 from 5 to 2
move 6 from 2 to 8
move 8 from 9 to 6
move 1 from 2 to 3
move 8 from 4 to 9
move 7 from 6 to 9
move 18 from 1 to 7
move 1 from 1 to 8
move 2 from 6 to 9
move 1 from 3 to 9
move 1 from 4 to 6
move 1 from 8 to 3
move 1 from 3 to 1
move 10 from 7 to 2
move 9 from 8 to 4
move 1 from 6 to 4
move 2 from 7 to 8
move 5 from 4 to 9
move 17 from 9 to 5
move 2 from 7 to 6
move 5 from 9 to 7
move 5 from 4 to 2
move 8 from 2 to 4
move 8 from 4 to 3
move 2 from 6 to 5
move 2 from 8 to 5
move 3 from 9 to 3
move 4 from 7 to 3
move 6 from 9 to 6
move 4 from 6 to 9
move 5 from 9 to 3
move 8 from 5 to 2
move 1 from 1 to 9
move 1 from 6 to 3
move 1 from 9 to 4
move 5 from 7 to 4
move 19 from 3 to 1
move 4 from 2 to 8
move 13 from 5 to 1
move 1 from 6 to 3
move 3 from 3 to 6
move 2 from 8 to 9
move 4 from 2 to 9
move 2 from 2 to 6
move 1 from 1 to 6
move 5 from 1 to 9
move 10 from 9 to 3
move 15 from 1 to 6
move 21 from 6 to 2
move 20 from 2 to 1
move 2 from 8 to 9
move 28 from 1 to 2
move 6 from 4 to 6
move 2 from 1 to 5
move 3 from 3 to 4
move 2 from 5 to 4
move 1 from 4 to 3
move 3 from 4 to 5
move 2 from 5 to 4
move 1 from 1 to 8
move 25 from 2 to 9
move 1 from 4 to 6
move 1 from 3 to 8
move 4 from 3 to 6
move 1 from 4 to 9
move 2 from 6 to 3
move 1 from 5 to 9
move 5 from 2 to 8
move 7 from 9 to 6
move 2 from 9 to 4
move 3 from 2 to 1
move 3 from 3 to 4
move 1 from 3 to 5
move 16 from 6 to 3
move 7 from 8 to 3
move 5 from 4 to 3
move 1 from 1 to 3
move 1 from 2 to 6
move 1 from 5 to 6
move 21 from 3 to 5
move 2 from 1 to 2
move 1 from 6 to 7
move 10 from 9 to 8
move 1 from 6 to 5
move 5 from 8 to 7
move 12 from 5 to 3
move 20 from 3 to 6
move 4 from 7 to 9
move 1 from 7 to 3
move 1 from 2 to 5
move 1 from 3 to 8
move 2 from 8 to 4
move 4 from 8 to 7
move 3 from 6 to 1
move 1 from 1 to 5
move 2 from 9 to 2
move 2 from 1 to 5
move 2 from 5 to 6
move 3 from 7 to 1
move 2 from 1 to 4
move 4 from 6 to 8
move 3 from 4 to 7
move 3 from 2 to 5
move 2 from 7 to 9
move 9 from 9 to 8
move 1 from 4 to 1
move 7 from 5 to 7
move 1 from 7 to 8
move 1 from 3 to 1
move 4 from 7 to 5
move 2 from 1 to 9
move 1 from 1 to 2
move 5 from 5 to 4
move 1 from 2 to 6
move 5 from 7 to 9
move 5 from 4 to 7
move 11 from 9 to 6
move 14 from 8 to 9
move 23 from 6 to 5
move 6 from 9 to 5
move 1 from 6 to 2
move 10 from 5 to 3
move 1 from 4 to 9
move 1 from 2 to 1
move 2 from 7 to 3
move 10 from 5 to 7
move 8 from 5 to 2
move 5 from 3 to 5
move 7 from 5 to 8
move 1 from 2 to 7
move 9 from 7 to 9
move 3 from 2 to 3
move 2 from 6 to 2
move 2 from 3 to 6
move 4 from 7 to 5
move 1 from 1 to 5
move 4 from 3 to 1
move 2 from 5 to 2
move 1 from 3 to 2
move 2 from 6 to 8
move 7 from 5 to 3
move 9 from 2 to 4
move 2 from 1 to 2
move 2 from 5 to 3
move 1 from 4 to 9
move 1 from 6 to 9
move 1 from 4 to 2
move 2 from 1 to 7
move 3 from 2 to 6
move 4 from 8 to 7
move 2 from 8 to 3
move 2 from 3 to 7
move 1 from 6 to 5
move 2 from 8 to 2
move 5 from 4 to 1
move 8 from 9 to 8
move 1 from 5 to 7
move 10 from 9 to 2
move 8 from 8 to 2
move 1 from 1 to 6
move 12 from 3 to 9
move 7 from 7 to 4
move 13 from 2 to 4
move 7 from 2 to 7
move 1 from 6 to 7
move 3 from 9 to 8
move 2 from 6 to 3
move 1 from 3 to 2
move 1 from 3 to 9
move 3 from 1 to 5
move 1 from 1 to 6
move 4 from 7 to 6
move 5 from 7 to 1
move 1 from 2 to 1
move 6 from 9 to 4
move 5 from 9 to 7
move 3 from 8 to 3
move 22 from 4 to 9
move 24 from 9 to 8
move 1 from 9 to 2
move 2 from 4 to 3
move 10 from 8 to 3
move 1 from 2 to 1
move 1 from 3 to 8
move 1 from 6 to 3
move 1 from 1 to 4
move 4 from 3 to 4
move 4 from 6 to 1
move 2 from 4 to 5
move 4 from 7 to 2
move 7 from 4 to 6
move 4 from 6 to 1
move 2 from 6 to 3
move 1 from 6 to 2
move 5 from 5 to 2
move 12 from 3 to 5
move 3 from 7 to 8
move 6 from 2 to 3
move 11 from 1 to 9
move 1 from 1 to 7
move 1 from 7 to 5
move 2 from 3 to 9
move 2 from 9 to 7
move 4 from 2 to 5
move 2 from 7 to 1
move 17 from 8 to 1
move 1 from 3 to 2
move 16 from 1 to 3
move 8 from 3 to 4
move 2 from 8 to 3
move 2 from 1 to 5
move 1 from 2 to 6
move 12 from 5 to 8
move 1 from 6 to 3
move 9 from 3 to 9
move 8 from 4 to 6
move 2 from 1 to 6
move 6 from 8 to 4
move 3 from 4 to 6
move 1 from 1 to 9
move 11 from 6 to 8
move 3 from 4 to 3
move 17 from 9 to 5
move 2 from 6 to 7
move 1 from 9 to 1
move 2 from 8 to 6
move 1 from 7 to 5
move 1 from 8 to 9
move 1 from 1 to 7
move 3 from 9 to 6
move 2 from 7 to 8
move 1 from 9 to 6
move 15 from 5 to 2
move 9 from 3 to 9
move 11 from 8 to 3
move 6 from 9 to 8
move 4 from 6 to 7
move 3 from 3 to 7
move 5 from 5 to 6
move 7 from 7 to 5
move 3 from 6 to 1
move 2 from 1 to 4
move 1 from 9 to 2
move 2 from 9 to 3
move 2 from 6 to 3
move 1 from 1 to 8
move 6 from 5 to 9
move 8 from 2 to 5
move 10 from 8 to 5
move 1 from 2 to 9
move 21 from 5 to 9
move 2 from 8 to 4
move 5 from 9 to 1
move 2 from 5 to 2
move 15 from 9 to 2
move 1 from 5 to 9
move 9 from 9 to 3
move 1 from 1 to 6
move 3 from 4 to 1
move 20 from 3 to 5
move 20 from 5 to 4
move 7 from 4 to 3
move 1 from 1 to 7
move 11 from 4 to 5
move 4 from 3 to 2
move 11 from 5 to 4
move 2 from 6 to 7
move 4 from 3 to 9
move 2 from 2 to 8
move 2 from 9 to 4
move 6 from 4 to 6
move 2 from 7 to 9
move 1 from 7 to 6
move 1 from 4 to 9
move 4 from 4 to 6
move 2 from 8 to 6
move 1 from 4 to 3
move 1 from 4 to 6
move 1 from 3 to 1
move 3 from 4 to 3
move 9 from 2 to 8
move 2 from 3 to 7
move 5 from 6 to 2
move 2 from 7 to 5
move 1 from 5 to 2
move 1 from 9 to 3
move 1 from 5 to 1
move 13 from 2 to 5
move 4 from 9 to 5
move 1 from 3 to 4
move 9 from 2 to 3
move 7 from 3 to 2
move 11 from 5 to 6
move 5 from 8 to 7
move 1 from 3 to 1
move 2 from 8 to 5
move 2 from 8 to 1
move 1 from 4 to 1
move 6 from 2 to 7
move 3 from 5 to 3
move 1 from 2 to 5
move 7 from 7 to 9
move 3 from 3 to 5
move 1 from 2 to 5
move 2 from 3 to 2
move 6 from 1 to 7
move 10 from 7 to 3
move 1 from 2 to 3
move 6 from 9 to 8
move 1 from 2 to 4
move 2 from 6 to 1
move 5 from 1 to 9
move 8 from 5 to 8
move 2 from 1 to 6
move 6 from 3 to 4
move 1 from 5 to 3
move 4 from 9 to 6
move 1 from 1 to 4
move 2 from 9 to 2
move 5 from 6 to 1
move 11 from 6 to 7
move 1 from 2 to 8
move 6 from 7 to 5
move 10 from 8 to 4
move 2 from 3 to 9
move 3 from 3 to 5
move 4 from 7 to 9
move 2 from 1 to 3
move 10 from 5 to 8
move 6 from 6 to 1
move 2 from 6 to 8
move 2 from 9 to 5
move 4 from 9 to 6
move 7 from 4 to 8
move 5 from 6 to 1
move 4 from 8 to 2
move 2 from 5 to 6
move 5 from 4 to 5
move 1 from 7 to 5
move 2 from 3 to 6
move 1 from 3 to 8
move 4 from 6 to 1
move 4 from 2 to 3
move 5 from 5 to 1
move 2 from 3 to 2
move 2 from 3 to 2
move 20 from 8 to 2
move 5 from 4 to 8
move 1 from 4 to 3
move 8 from 2 to 1
move 1 from 5 to 6
move 5 from 2 to 3
move 1 from 6 to 5
move 5 from 3 to 2
move 1 from 3 to 7
move 6 from 8 to 5
move 13 from 2 to 9
move 7 from 9 to 8
move 1 from 7 to 8
move 5 from 8 to 3
move 2 from 2 to 5
move 2 from 8 to 4
move 27 from 1 to 5
move 1 from 2 to 3
move 5 from 3 to 1
move 22 from 5 to 7
move 1 from 8 to 5
move 1 from 3 to 2
move 7 from 1 to 3
move 2 from 3 to 7
move 2 from 2 to 4
move 5 from 9 to 1
move 5 from 3 to 9
move 3 from 1 to 5
move 3 from 1 to 6
move 3 from 6 to 3
move 4 from 4 to 2
move 8 from 5 to 3
move 8 from 7 to 4
move 14 from 7 to 4
move 1 from 1 to 7
move 6 from 9 to 6
move 7 from 5 to 3
move 14 from 3 to 6
move 2 from 2 to 1
move 4 from 3 to 7
move 6 from 7 to 6
move 1 from 7 to 6
move 1 from 5 to 1
move 2 from 1 to 5
move 3 from 5 to 7
move 8 from 6 to 5
move 5 from 5 to 1
move 1 from 7 to 3
move 1 from 3 to 8
move 22 from 4 to 7
move 7 from 6 to 3
move 4 from 3 to 2
move 3 from 1 to 3
move 17 from 7 to 6
move 1 from 8 to 1
move 2 from 2 to 4
move 3 from 7 to 2
move 2 from 2 to 9
move 1 from 1 to 8
move 2 from 3 to 1
move 6 from 6 to 8
move 2 from 9 to 2
move 4 from 5 to 1
move 5 from 8 to 9
move 1 from 7 to 3
move 4 from 3 to 4
move 1 from 7 to 4
move 4 from 9 to 7
move 5 from 7 to 9
move 1 from 7 to 3
move 2 from 2 to 8
move 5 from 4 to 2
move 21 from 6 to 8
move 2 from 3 to 8
move 23 from 8 to 6
move 1 from 2 to 6
move 2 from 9 to 8
move 22 from 6 to 7
move 2 from 9 to 3
move 2 from 3 to 7
move 2 from 1 to 6
move 1 from 2 to 5
move 3 from 1 to 3
move 6 from 7 to 4
move 5 from 8 to 5
move 1 from 3 to 8
move 1 from 9 to 3
move 6 from 4 to 8
move 1 from 5 to 3
move 6 from 2 to 8
move 15 from 7 to 5
move 1 from 7 to 1
move 14 from 5 to 8
move 1 from 4 to 9
move 5 from 1 to 7
move 3 from 6 to 2
move 4 from 5 to 6
move 1 from 4 to 8
move 4 from 3 to 1
move 2 from 9 to 2
move 7 from 7 to 1
move 7 from 2 to 7
move 9 from 8 to 6
move 7 from 7 to 1
move 12 from 6 to 8
move 25 from 8 to 6
move 3 from 8 to 1
move 28 from 6 to 2
move 15 from 2 to 3
move 1 from 5 to 4
move 3 from 2 to 7
move 6 from 2 to 9

253
src/days/day05/mod.rs Normal file
View file

@ -0,0 +1,253 @@
use super::template::{DayTrait, ResultType};
use std::num::ParseIntError;
use thiserror::Error;
const DAY_NUMBER: usize = 5;
pub struct Day;
impl DayTrait for Day {
fn get_day_number(&self) -> usize {
DAY_NUMBER
}
fn part1(&self, lines: &[String]) -> anyhow::Result<ResultType> {
let (mut stacks, commands) = parse(lines)?;
for command in commands {
command.with_turn(&mut stacks)?;
}
Ok(ResultType::String(get_word(&stacks)))
}
fn part2(&self, lines: &[String]) -> anyhow::Result<ResultType> {
let (mut stacks, commands) = parse(lines)?;
for command in commands {
command.without_turn(&mut stacks)?;
}
Ok(ResultType::String(get_word(&stacks)))
}
}
#[derive(Debug, Error)]
enum CrateError {
#[error("Illegal move: {0}")]
IllegalMove(String),
#[error("Cant Parse Integer in Move")]
NotAnInteger(#[from] ParseIntError),
#[error("No crate stacks given")]
NoCargoStacksGiven,
#[error("Illegal move: Too few stacks have {0} needed {1}")]
TooFewStacks(usize, usize),
#[error("Illegal move: Too few crates have {0} needed {1}")]
TooFewCrates(String, usize),
#[error("Stack number must not be 0")]
NoZeroStack,
}
fn parse_crate(line: &str) -> Vec<Option<char>> {
line.chars()
.skip(1)
.step_by(4)
.map(|c| if c == ' ' { None } else { Some(c) })
.collect()
}
fn parse_all_crates(line_it: &mut dyn Iterator<Item = &String>) -> Result<Vec<String>, CrateError> {
let rows: Vec<_> = line_it
.take_while(|line| !line.is_empty())
.map(|row| parse_crate(row))
.collect();
let Some(stacks_count) = rows.iter().map(|row| row.len()).max() else {
return Err(CrateError::NoCargoStacksGiven);
};
let mut stacks = Vec::with_capacity(stacks_count);
for stack_num in 0..stacks_count {
let mut stack = String::from("");
for row in &rows {
if let Some(Some(one_crate)) = row.get(stack_num) {
stack.push(*one_crate);
}
}
stacks.push(stack);
}
Ok(stacks)
}
fn parse(line: &[String]) -> Result<(Vec<String>, Vec<Move>), CrateError> {
let mut iter = line.iter();
let stacks = parse_all_crates(&mut iter)?;
let moves: Vec<_> = iter
.map(|command| Move::try_from(command.as_str()))
.collect::<Result<_, _>>()?;
Ok((stacks, moves))
}
fn get_word(stacks: &[String]) -> String {
stacks
.iter()
.map(|stack| stack.chars().next().unwrap())
.collect::<String>()
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct Move {
from_stack: usize,
to_stack: usize,
amount: usize,
}
impl Move {
pub fn new(amount: usize, from_stack: usize, to_stack: usize) -> Move {
Move {
amount,
from_stack,
to_stack,
}
}
fn apply_single(
&self,
stacks: &mut Vec<String>,
func: fn(&str) -> String,
) -> Result<(), CrateError> {
if self.to_stack >= stacks.len() {
return Err(CrateError::TooFewStacks(stacks.len(), self.to_stack));
}
let Some(from_stack) = stacks.get(self.from_stack ) else {
return Err(CrateError::TooFewStacks(stacks.len(), self.from_stack));
};
if from_stack.len() < self.amount {
return Err(CrateError::TooFewCrates(from_stack.to_owned(), self.amount));
}
let from_stack = from_stack.to_owned();
let (start, end) = from_stack.split_at(self.amount);
stacks[self.from_stack] = end.to_owned();
stacks[self.to_stack] = format!("{}{}", func(start), stacks[self.to_stack]);
Ok(())
}
pub fn with_turn(&self, stacks: &mut Vec<String>) -> Result<(), CrateError> {
self.apply_single(stacks, |crates| crates.chars().rev().collect())
}
pub fn without_turn(&self, stacks: &mut Vec<String>) -> Result<(), CrateError> {
self.apply_single(stacks, |crates| crates.to_owned())
}
}
impl TryFrom<&str> for Move {
type Error = CrateError;
fn try_from(value: &str) -> Result<Self, Self::Error> {
let parts: Vec<_> = value.split_whitespace().collect();
if parts.len() != 6 {
return Err(CrateError::IllegalMove(value.to_owned()));
}
let amount: usize = parts[1].parse()?;
let from_stack: usize = parts[3].parse()?;
let to_stack: usize = parts[5].parse()?;
if from_stack == 0 || to_stack == 0 {
return Err(CrateError::NoZeroStack);
}
Ok(Move::new(amount, from_stack - 1, to_stack - 1))
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::common::file::read_lines;
use anyhow::Result;
#[test]
fn test_parse_crates() -> Result<()> {
let line = " [D] ";
let expected = vec![None, Some('D'), None];
let result = parse_crate(line);
assert_eq!(result, expected);
Ok(())
}
#[test]
fn test_parse_move() -> Result<()> {
let line = "move 3 from 2 to 1";
let expected = Move::new(3, 1, 0);
let result = Move::try_from(line)?;
assert_eq!(result, expected);
Ok(())
}
#[test]
fn test_parse_all_crates() -> Result<()> {
let lines = vec![
" [D] ".to_owned(),
"[N] [C] ".to_owned(),
"[Z] [M] [P]".to_owned(),
" 1 2 3 ".to_owned(),
"".to_owned(),
"move 1 from to 2 1".to_owned(),
];
let mut input = lines.iter();
let expected = vec!["NZ1".to_owned(), "DCM2".to_owned(), "P3".to_owned()];
let result = parse_all_crates(&mut input)?;
assert_eq!(result, expected);
Ok(())
}
#[test]
fn test_with_turn() -> Result<()> {
let mut stacks = vec!["NZ1".to_owned(), "DCM2".to_owned(), "P3".to_owned()];
let command = Move::new(2, 1, 0);
let expected = vec!["CDNZ1".to_owned(), "M2".to_owned(), "P3".to_owned()];
command.with_turn(&mut stacks)?;
assert_eq!(stacks, expected);
Ok(())
}
#[test]
fn test_part1() -> Result<()> {
let day = Day {};
let lines = read_lines(day.get_day_number(), "example01.txt")?;
let expected = ResultType::String("CMZ".to_owned());
let result = day.part1(&lines)?;
assert_eq!(result, expected);
Ok(())
}
#[test]
fn test_without_turn() -> Result<()> {
let mut stacks = vec!["NZ1".to_owned(), "DCM2".to_owned(), "P3".to_owned()];
let command = Move::new(2, 1, 0);
let expected = vec!["DCNZ1".to_owned(), "M2".to_owned(), "P3".to_owned()];
command.without_turn(&mut stacks)?;
assert_eq!(stacks, expected);
Ok(())
}
#[test]
fn test_part2() -> Result<()> {
let day = Day {};
let lines = read_lines(day.get_day_number(), "example01.txt")?;
let expected = ResultType::String("MCD".to_owned());
let result = day.part2(&lines)?;
assert_eq!(result, expected);
Ok(())
}
}

View file

@ -2,6 +2,7 @@ mod day01;
mod day02;
mod day03;
mod day04;
mod day05;
mod template;
pub use template::DayTrait;
@ -11,7 +12,7 @@ pub mod day_provider {
use super::*;
use thiserror::Error;
const MAX_DAY: usize = 4;
const MAX_DAY: usize = 5;
pub fn get_day(day_num: usize) -> Result<Box<dyn DayTrait>, ProviderError> {
match day_num {
@ -19,6 +20,7 @@ pub mod day_provider {
2 => Ok(Box::new(day02::Day)),
3 => Ok(Box::new(day03::Day)),
4 => Ok(Box::new(day04::Day)),
5 => Ok(Box::new(day05::Day)),
_ => Err(ProviderError::InvalidNumber(day_num)),
}
}