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