aboutsummaryrefslogtreecommitdiff
path: root/day2/src
diff options
context:
space:
mode:
Diffstat (limited to 'day2/src')
-rw-r--r--day2/src/main.rs135
1 files changed, 135 insertions, 0 deletions
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());
+ }
+}