day03 finished

This commit is contained in:
Ruediger Ludwig 2023-01-28 06:00:12 +01:00
parent eb1ce68486
commit d7c85a75f6
8 changed files with 534 additions and 37 deletions

144
src/days/day03/mod.rs Normal file
View file

@ -0,0 +1,144 @@
use itertools::Itertools;
use thiserror::Error;
use super::template::{DayTrait, ResultType};
const DAY_NUMBER: usize = 3;
pub struct Day;
impl DayTrait for Day {
fn get_day_number(&self) -> usize {
DAY_NUMBER
}
fn part1(&self, lines: &str) -> anyhow::Result<ResultType> {
let sum = lines
.split('\n')
.map(|rucksack| find_double(rucksack).and_then(priority))
.collect::<Result<Vec<_>, _>>()?
.iter()
.sum();
Ok(ResultType::IntResult(sum))
}
fn part2(&self, lines: &str) -> anyhow::Result<ResultType> {
let sum = lines
.split('\n')
.chunks(3)
.into_iter()
.map(|chunk| find_badge(&chunk.collect::<Vec<_>>()).and_then(priority))
.collect::<Result<Vec<_>, _>>()?
.iter()
.sum();
Ok(ResultType::IntResult(sum))
}
}
#[derive(Debug, Error)]
enum RucksackError {
#[error("No double item found")]
NoDoubleFound,
#[error("Not a valid char: {0}")]
InvalidChar(char),
#[error("Need at least two elves for common item")]
NeedAtLeastTwo,
#[error("No common badge was found")]
NoBadgeFound,
}
fn priority(c: char) -> Result<i64, RucksackError> {
match c {
'a'..='z' => Ok(c as i64 - 'a' as i64 + 1),
'A'..='Z' => Ok(c as i64 - 'A' as i64 + 27),
_ => Err(RucksackError::InvalidChar(c)),
}
}
fn find_double(content: &str) -> Result<char, RucksackError> {
let length = content.len() / 2;
let part1 = &content[..length];
let part2 = &content[length..];
for c in part1.chars() {
if part2.contains(c) {
return Ok(c);
}
}
Err(RucksackError::NoDoubleFound)?
}
fn find_badge<'a>(elves: &[&str]) -> Result<char, RucksackError> {
if elves.len() < 2 {
return Err(RucksackError::NeedAtLeastTwo);
};
for c in elves[0].chars() {
let mut found = true;
for other in &elves[1..] {
if !other.contains(c) {
found = false;
}
}
if found {
return Ok(c);
}
}
Err(RucksackError::NoBadgeFound)
}
#[cfg(test)]
mod test {
use super::*;
use crate::common::file::read_data;
use anyhow::Result;
#[test]
fn test_rucksack() -> Result<(), RucksackError> {
let input = "vJrwpWtwJgWrhcsFMMfFFhFp";
let expected = 16;
let result = find_double(input).and_then(priority)?;
assert_eq!(result, expected);
Ok(())
}
#[test]
fn test_part1() -> Result<()> {
let day = Day {};
let lines = read_data(day.get_day_number(), "example01.txt")?;
let expected = ResultType::IntResult(157);
let result = day.part1(&lines)?;
assert_eq!(result, expected);
Ok(())
}
#[test]
fn test_find_badge() -> Result<(), RucksackError> {
let input = vec![
"vJrwpWtwJgWrhcsFMMfFFhFp",
"jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL",
"PmmdzqPrVvPwwTWBwg",
];
let expected = 18;
let result = find_badge(&input).and_then(priority)?;
assert_eq!(result, expected);
Ok(())
}
#[test]
fn test_part2() -> Result<()> {
let day = Day {};
let lines = read_data(day.get_day_number(), "example01.txt")?;
let expected = ResultType::IntResult(70);
let result = day.part2(&lines)?;
assert_eq!(result, expected);
Ok(())
}
}