diff options
| -rw-r--r-- | Cargo.lock | 4 | ||||
| -rw-r--r-- | Cargo.toml | 2 | ||||
| -rw-r--r-- | day2/Cargo.toml | 6 | ||||
| -rw-r--r-- | day2/src/main.rs | 135 |
4 files changed, 146 insertions, 1 deletions
@@ -14,3 +14,7 @@ version = "0.1.0" dependencies = [ "anyhow", ] + +[[package]] +name = "day2" +version = "0.1.0" @@ -1,3 +1,3 @@ [workspace] resolver = "3" -members = ["day1"] +members = ["day1", "day2"] diff --git a/day2/Cargo.toml b/day2/Cargo.toml new file mode 100644 index 0000000..6c22320 --- /dev/null +++ b/day2/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "day2" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/day2/src/main.rs b/day2/src/main.rs new file mode 100644 index 0000000..5bb661f --- /dev/null +++ b/day2/src/main.rs @@ -0,0 +1,135 @@ +use std::{env, fs, num::ParseIntError, ops::Range, str::FromStr}; + +#[derive(Debug, Clone, Copy)] +struct IDRange(u64, u64); + +#[derive(Debug)] +struct ParseIDRangeError; + +impl From<ParseIntError> for ParseIDRangeError { + fn from(_: ParseIntError) -> Self { + Self + } +} + +impl FromStr for IDRange { + type Err = ParseIDRangeError; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + let (start, end) = s.split_once('-').ok_or(ParseIDRangeError)?; + Ok(Self(start.parse()?, end.parse()?)) + } +} + +struct IDRangeIntoIter { + range: IDRange, + cur: u64, +} + +impl Iterator for IDRangeIntoIter { + type Item = ID; + + fn next(&mut self) -> Option<Self::Item> { + if self.cur <= self.range.1 { + let id = ID(self.cur); + self.cur += 1; + Some(id) + } else { + None + } + } +} + +impl IntoIterator for IDRange { + type Item = ID; + + type IntoIter = IDRangeIntoIter; + + fn into_iter(self) -> Self::IntoIter { + Self::IntoIter { + cur: self.0, + range: self, + } + } +} + +#[derive(Debug, PartialEq, Eq)] +struct ID(u64); + +impl ID { + fn is_invalid(&self) -> bool { + let s = self.0.to_string(); + s.len() % 2 == 0 && { + let (a, b) = s.split_at(s.len() / 2); + a == b + } + } +} + +#[derive(Debug)] +enum Error { + BadArgument, + BadRange(String), +} + +impl From<std::io::Error> for Error { + fn from(_: std::io::Error) -> Self { + Self::BadArgument + } +} + +fn main() -> Result<(), Error> { + let x: Range<u32> = 0..99; + let mut args = env::args(); + let input_path = args.nth(1).ok_or_else(|| Error::BadArgument)?; + let input = fs::read_to_string(input_path)?; + + let ranges: Vec<IDRange> = input + .split_whitespace() + .flat_map(|s| s.split(',')) + .filter(|s| s.len() != 0) + .map(|s| s.parse().map_err(|_| Error::BadRange(s.into()))) + .collect::<Result<_, _>>()?; + + let result: u64 = ranges + .iter() + .flat_map(|range| range.into_iter().filter(ID::is_invalid).map(|id| id.0)) + .sum(); + + println!("Result: {}", result); + + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn parse_id_range() -> Result<(), ParseIDRangeError> { + let range: IDRange = "99-100".parse()?; + assert_eq!(range.0, 99); + assert_eq!(range.1, 100); + Ok(()) + } + + #[test] + fn id_range_into_iter() { + let range = IDRange(2, 4); + let ids: Vec<ID> = range.into_iter().collect(); + assert_eq!(ids, vec![ID(2), ID(3), ID(4)]); + } + + #[test] + fn id_is_valid() { + assert!(!ID(0).is_invalid()); + assert!(!ID(1).is_invalid()); + assert!(!ID(2).is_invalid()); + assert!(!ID(10).is_invalid()); + assert!(!ID(12).is_invalid()); + assert!(!ID(21).is_invalid()); + + assert!(ID(11).is_invalid()); + assert!(ID(5555).is_invalid()); + } +} |
