From cc5d08c90d6201e0d66eb9d075697e8254cf49cb Mon Sep 17 00:00:00 2001 From: Burnus Date: Fri, 12 May 2023 20:53:04 +0200 Subject: [PATCH] Cleanup for 2022 day 3: Turned into a lib and introduced parse errors --- 2022/day03-rucksack_reorganization/src/lib.rs | 86 +++++++++++++++++++ .../day03-rucksack_reorganization/src/main.rs | 68 --------------- .../tests/{input => challenge_input} | 0 3 files changed, 86 insertions(+), 68 deletions(-) create mode 100644 2022/day03-rucksack_reorganization/src/lib.rs delete mode 100644 2022/day03-rucksack_reorganization/src/main.rs rename 2022/day03-rucksack_reorganization/tests/{input => challenge_input} (100%) diff --git a/2022/day03-rucksack_reorganization/src/lib.rs b/2022/day03-rucksack_reorganization/src/lib.rs new file mode 100644 index 0000000..44b9215 --- /dev/null +++ b/2022/day03-rucksack_reorganization/src/lib.rs @@ -0,0 +1,86 @@ +use std::collections::HashSet; +use core::fmt::Display; + +#[derive(Debug, PartialEq, Eq)] +pub enum ParseError { + InvalidToken(char), +} + +impl Display for ParseError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::InvalidToken(t) => write!(f, "Invalid Item encountered: {t}"), + } + } +} + +pub fn run(input: &str) -> Result<(u32, u32), ParseError> { + let first = input.lines().map(duplicate_prio).sum::>()?; + let second = get_badge_prios(input)?; + Ok((first, second)) +} + +fn item_priority(item: char) -> Result { + match item { + lc if lc.is_ascii_lowercase() => Ok(lc as u32 - 96), + uc if uc.is_ascii_uppercase() => Ok(uc as u32 - 38), + e => Err(ParseError::InvalidToken(e)), + } +} + +fn duplicate_prio(line: &str) -> Result { + if line.len() % 2 != 0 { + panic!("Odd number of items!"); + } + let comp1 = &line[..line.len()/2].chars().collect::>(); + let comp2 = &line[line.len()/2..].chars().collect::>(); + + comp1.iter() + .filter(|c| comp2.contains(*c)) + .map(|c| item_priority(*c)) + .sum() +} + +fn badge_prio(e1: &str, e2: &str, e3: &str) -> Result { + e1.chars() + .filter(|c| e2.contains(*c) && e3.contains(*c)) + .map(item_priority) + .max_by(|a, b| match (a, b) { + (Ok(a), Ok(b)) => a.cmp(b), + (Ok(_), _err) => std::cmp::Ordering::Less, + (_err, _) => std::cmp::Ordering::Greater, + }) + .unwrap() +} + +fn get_badge_prios(list: &str) -> Result { + let mut badge_prios = 0; + let mut iter = list.lines(); + while let (Some(e1), Some(e2), Some(e3)) = (iter.next(), iter.next(), iter.next()) { + let this_badge = badge_prio(e1, e2, e3); + badge_prios += this_badge?; + } + Ok(badge_prios) +} + +#[cfg(test)] +mod tests { + use super::*; + use std::fs::read_to_string; + + fn read_file(name: &str) -> String { + read_to_string(name).expect(&format!("Unable to read file: {name}")[..]).trim().to_string() + } + + #[test] + fn test_sample() { + let sample_input = read_file("tests/sample_input"); + assert_eq!(run(&sample_input), Ok((157, 70))); + } + + #[test] + fn test_challenge() { + let challenge_input = read_file("tests/challenge_input"); + assert_eq!(run(&challenge_input), Ok((7746, 2604))); + } +} diff --git a/2022/day03-rucksack_reorganization/src/main.rs b/2022/day03-rucksack_reorganization/src/main.rs deleted file mode 100644 index 2894944..0000000 --- a/2022/day03-rucksack_reorganization/src/main.rs +++ /dev/null @@ -1,68 +0,0 @@ -use std::collections::HashSet; -use std::fs; - -fn read_file(path: &str) -> String { - fs::read_to_string(path) - .expect("File not Found") -} - -fn item_priority(item: char) -> u32 { - match item { - lc if ('a'..='z').contains(&lc) => lc as u32 - 96, - uc if ('A'..='Z').contains(&uc) => uc as u32 - 38, - _ => panic!("Unexpected Token"), - } -} - -fn duplicate_prio(line: &str) -> u32 { - if line.len() % 2 != 0 { - panic!("Odd number of items!"); - } - let comp1 = &line[..line.len()/2].chars().collect::>(); - let comp2 = &line[line.len()/2..].chars().collect::>(); - - comp1.iter() - .filter(|c| comp2.contains(*c)) - .map(|c| item_priority(*c)) - .sum() -} - -fn badge_prio(e1: &str, e2: &str, e3: &str) -> u32 { - e1.chars() - .filter(|c| e2.contains(*c) && e3.contains(*c)) - .map(item_priority) - .max() - .unwrap() -} - -fn get_badge_prios(list: &str) -> u32 { - let mut badge_prios = 0; - let mut iter = list.lines(); - while let (Some(e1), Some(e2), Some(e3)) = (iter.next(), iter.next(), iter.next()) { - badge_prios += badge_prio(e1, e2, e3); - } - badge_prios -} - -fn main() { - let contents = read_file("input"); - - let duplicate_prios: u32 = contents.lines().map(duplicate_prio).sum(); - let badge_prios = get_badge_prios(&contents); - println!("Priorities of Duplicates: {duplicate_prios}"); - println!("Badge Priorities: {badge_prios}"); -} - -#[test] -fn sample_input() { - let contents = read_file("tests/sample_input"); - assert_eq!(contents.lines().map(duplicate_prio).sum::(), 157); - assert_eq!(get_badge_prios(&contents), 70); -} - -#[test] -fn challenge_input() { - let contents = read_file("tests/input"); - assert_eq!(contents.lines().map(duplicate_prio).sum::(), 7746); - assert_eq!(get_badge_prios(&contents), 2604); -} diff --git a/2022/day03-rucksack_reorganization/tests/input b/2022/day03-rucksack_reorganization/tests/challenge_input similarity index 100% rename from 2022/day03-rucksack_reorganization/tests/input rename to 2022/day03-rucksack_reorganization/tests/challenge_input