diff --git a/2022/Cargo.toml b/2022/Cargo.toml index dd3d9c5..da1fc22 100644 --- a/2022/Cargo.toml +++ b/2022/Cargo.toml @@ -15,6 +15,10 @@ path = "src/day1.rs" name = "day2" path = "src/day2.rs" +[[bin]] +name = "day3" +path = "src/day3.rs" + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] diff --git a/2022/src/day3.rs b/2022/src/day3.rs new file mode 100644 index 0000000..6659ccf --- /dev/null +++ b/2022/src/day3.rs @@ -0,0 +1,103 @@ +use std::str::FromStr; + + +const DATA: &'static str = include_str!("../data/day3.txt"); +// const DATA: &'static str = " +// vJrwpWtwJgWrhcsFMMfFFhFp +// jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL +// PmmdzqPrVvPwwTWBwg +// wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn +// ttgJtRGJQctTZtZT +// CrZsJsPPZsGzwwsLwLmpwMDw +// "; + + +#[derive(Debug)] +enum DataError { + Imbalanced, + UnknownValue, + NoDuplicate, + NoTriplicate, + ShortGroup, +} + + +struct Rucksack { + left: Vec, + right: Vec, +} + +impl Rucksack { + fn find_duplicate(&self) -> Option { + // pretty sure this is faster than hash set, given the sizes involved + self.left.iter() + .find(|c| self.right.contains(c)) + .map(|c| *c) + } + + fn iter_all(&self) -> impl Iterator { + self.left.iter().chain(self.right.iter()) + } + + fn contains(&self, v: u8) -> bool { + self.left.contains(&v) || self.right.contains(&v) + } +} + +impl FromStr for Rucksack { + type Err = DataError; + + fn from_str(line: &str) -> Result { + let line = line.trim(); + if line.len() % 2 != 0 { + return Err(DataError::Imbalanced); + } + let (a, b) = line.as_bytes().split_at(line.len() / 2); + Ok(Rucksack { + left: a.into(), + right: b.into(), + }) + } +} + + +fn priority(c: u8) -> Result { + match c { + // lowercase + 97..=122 => Ok(c as u64 - 96), + // uppercase + 65..=90 => Ok(c as u64 - 38), + _ => Err(DataError::UnknownValue), + } +} + + +fn main() -> Result<(), DataError> { + let mut dup_total = 0; + let rucks = DATA.trim() + .split("\n") + .map(|line| Rucksack::from_str(line)) + .collect::, DataError>>()?; + + for ruck in rucks.iter() { + let dup = ruck.find_duplicate() + .ok_or(DataError::NoDuplicate)?; + dup_total += priority(dup)?; + } + println!("Part 1: {dup_total}"); + + let mut groups_total = 0; + for (idx, ruck) in rucks.iter().enumerate().step_by(3) { + if idx > rucks.len() - 3 { + return Err(DataError::ShortGroup); + } + + let badge = *ruck.iter_all() + .find(|&v| rucks[idx + 1].contains(*v) && rucks[idx + 2].contains(*v)) + .ok_or(DataError::NoTriplicate)?; + groups_total += priority(badge)?; + } + println!("Part 2: {groups_total}"); + + Ok(()) +} \ No newline at end of file diff --git a/2022/src/lib.rs b/2022/src/lib.rs index 20aff69..e69de29 100644 --- a/2022/src/lib.rs +++ b/2022/src/lib.rs @@ -1,12 +0,0 @@ -#[allow(unused_macros)] -macro_rules! get_data { - ($filename: literal) => { - include_str!(concat!("../data/", $filename, ".txt")) - } -} - - -#[allow(dead_code)] -fn main() { - todo!(); -}