use std::{env, fs, num::ParseIntError, ops::Range, str::FromStr}; #[derive(Debug, Clone, Copy)] struct IDRange(u64, u64); #[derive(Debug)] struct ParseIDRangeError; impl From for ParseIDRangeError { fn from(_: ParseIntError) -> Self { Self } } impl FromStr for IDRange { type Err = ParseIDRangeError; fn from_str(s: &str) -> Result { 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 { 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_simple(&self) -> bool { let s = self.0.to_string(); s.len() % 2 == 0 && { let (a, b) = s.split_at(s.len() / 2); a == b } } fn is_invalid(&self) -> bool { let s = self.0.to_string(); if s.len() <= 1 { return false; } let chars: Vec = s.chars().collect(); let mut i = 1; let mut j = 0; loop { if i == chars.len() - 1 { return chars[i] == chars[j] && chars.len() % (i - j) == 0; } if chars[i] == chars[j] { j += 1; } else { j = 0; } i += 1; } } } #[derive(Debug)] enum Error { BadArgument, BadRange(String), } impl From for Error { fn from(_: std::io::Error) -> Self { Self::BadArgument } } fn main() -> Result<(), Error> { let x: Range = 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 = input .split_whitespace() .flat_map(|s| s.split(',')) .filter(|s| s.len() != 0) .map(|s| s.parse().map_err(|_| Error::BadRange(s.into()))) .collect::>()?; let result_simple: u64 = ranges .iter() .flat_map(|range| { range .into_iter() .filter(ID::is_invalid_simple) .map(|id| id.0) }) .sum(); let result: u64 = ranges .iter() .flat_map(|range| range.into_iter().filter(ID::is_invalid).map(|id| id.0)) .sum(); println!("Result (simple): {}", result_simple); 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 = range.into_iter().collect(); assert_eq!(ids, vec![ID(2), ID(3), ID(4)]); } #[test] fn id_is_invalid_simple() { assert!(!ID(0).is_invalid_simple()); assert!(!ID(1).is_invalid_simple()); assert!(!ID(2).is_invalid_simple()); assert!(!ID(10).is_invalid_simple()); assert!(!ID(12).is_invalid_simple()); assert!(!ID(21).is_invalid_simple()); assert!(ID(11).is_invalid_simple()); assert!(ID(5555).is_invalid_simple()); } #[test] fn id_is_invalid() { assert!(!ID(1).is_invalid()); assert!(!ID(12).is_invalid()); assert!(!ID(121).is_invalid()); assert!(!ID(1214).is_invalid()); assert!(!ID(123121).is_invalid()); assert!(ID(11).is_invalid()); assert!(ID(1212).is_invalid()); assert!(ID(111).is_invalid()); assert!(ID(123123).is_invalid()); assert!(ID(121212).is_invalid()); assert!(ID(1010).is_invalid()); } }