day 4: [rust] part 1
authorPat Thoyts <pat.thoyts@gmail.com>
Mon, 4 Dec 2023 18:54:10 +0000 (18:54 +0000)
committerPat Thoyts <pat.thoyts@gmail.com>
Mon, 4 Dec 2023 18:54:10 +0000 (18:54 +0000)
day4/Cargo.toml [new file with mode: 0644]
day4/src/card.rs [new file with mode: 0644]
day4/src/main.rs [new file with mode: 0644]

diff --git a/day4/Cargo.toml b/day4/Cargo.toml
new file mode 100644 (file)
index 0000000..72192b1
--- /dev/null
@@ -0,0 +1,3 @@
+[package]\r
+name = "aoc2023-day4"\r
+version = "1.0.0"\r
diff --git a/day4/src/card.rs b/day4/src/card.rs
new file mode 100644 (file)
index 0000000..9dad87a
--- /dev/null
@@ -0,0 +1,89 @@
+use std::str::FromStr;\r
+\r
+#[derive(Debug, PartialEq)]\r
+pub struct Card {\r
+    pub id: u32,\r
+    pub count: u32,\r
+    pub winning: Vec<u32>,\r
+    pub numbers: Vec<u32>,\r
+}\r
+\r
+#[derive(Debug, PartialEq, Eq)]\r
+pub struct ParseCardError;\r
+\r
+impl Card {\r
+    // part 1: calculate the number of points for this card.\r
+    pub fn points(&self) -> u32 {\r
+        let mut points: u32 = 0;\r
+        for _vals in self.numbers.iter().filter(|x| self.winning.contains(x)) {\r
+            if points == 0 {\r
+                points = 1;\r
+            } else {\r
+                points *= 2;\r
+            }\r
+        }\r
+        return points;\r
+    }\r
+\r
+    // returns the number of winning numbers\r
+    pub fn matches(&self) -> u32 {\r
+        self.numbers.iter()\r
+            .filter(|x| self.winning.contains(x)).count() as u32\r
+    }\r
+\r
+    pub fn match_nums(&self) -> Vec<u32> {\r
+        let mut result = Vec::<u32>::new();\r
+        for num in &self.numbers {\r
+            if self.winning.contains(num) {\r
+                result.push(*num);\r
+            }\r
+        }\r
+        return result;\r
+    }\r
+}\r
+\r
+impl FromStr for Card {\r
+    type Err = ParseCardError;\r
+\r
+    fn from_str(s: &str) -> Result<Self, Self::Err> {\r
+        let (name, nums) = s.trim().split_once(':').ok_or(ParseCardError)?;\r
+        let (_junk, idstr) = name.split_once(" ").unwrap();\r
+        let id = idstr.trim().parse().unwrap();\r
+        let (wins, vals) = nums.split_once("|").unwrap();\r
+        let winning: Vec<u32> = wins.trim().split_whitespace().map(|x| x.parse::<u32>().unwrap()).collect();\r
+        let values: Vec<u32> = vals.trim().split_whitespace().map(|x| x.parse::<u32>().unwrap()).collect();\r
+        Ok( Card {id: id, count: 1, winning: winning, numbers: values} )\r
+    }\r
+}\r
+\r
+#[cfg(test)]\r
+mod test {\r
+    use super::*;\r
+\r
+    #[test]\r
+    fn test_parse() {\r
+        let card = "Card 1: 41 48 83 86 17 | 83 86  6 31 17  9 48 53".parse::<Card>().unwrap();\r
+        assert_eq!(card.id, 1);\r
+        assert_eq!(card.winning, vec![41, 48, 83, 86, 17]);\r
+        assert_eq!(card.numbers, vec![83, 86, 6, 31, 17, 9, 48, 53]);\r
+    }\r
+\r
+    #[test]\r
+    fn test_points() {\r
+        let card = "Card 1: 41 48 83 86 17 | 83 86  6 31 17  9 48 53".parse::<Card>().unwrap();\r
+        assert_eq!(card.points(), 8);\r
+    }\r
+\r
+    #[test]\r
+    fn test_matches() {\r
+        let card = "Card 1: 41 48 83 86 17 | 83 86  6 31 17  9 48 53".parse::<Card>().unwrap();\r
+        assert_eq!(card.matches(), 4);\r
+    }\r
+\r
+    #[test]\r
+    fn test_count_change() {\r
+        let mut card = Card {id: 1, count: 1, winning: vec![], numbers: vec![] };\r
+        card.count += 1;\r
+        assert_eq!(card.count, 2);\r
+    }\r
+}
\ No newline at end of file
diff --git a/day4/src/main.rs b/day4/src/main.rs
new file mode 100644 (file)
index 0000000..20d9bfc
--- /dev/null
@@ -0,0 +1,26 @@
+pub mod card;\r
+\r
+use card::Card;\r
+\r
+use std::error::Error;\r
+use std::env;\r
+use std::fs::File;\r
+use std::io::{prelude::*, BufReader};\r
+\r
+fn main() -> Result<(), Box<dyn Error>> {\r
+    let args: Vec<String> = env::args().collect();\r
+    if args.len() > 1 {\r
+        let input = File::open(&args[1]).expect("no such file");\r
+        let buffered = BufReader::new(input);\r
+        let cards: Vec<Card> = buffered.lines()\r
+            .map(|x| x.expect("something").parse::<Card>().unwrap())\r
+            .collect();\r
+        for card in &cards {\r
+            println!("{:?}", card);\r
+        }\r
+        let points: u32 = cards.iter().map(|c| c.points()).sum();\r
+        println!("part 1: {}", points);\r
+\r
+    }\r
+    Ok(())\r
+}\r