diff --git a/2023/day4/src/main.rs b/2023/day4/src/main.rs index 529d362..40e65ee 100644 --- a/2023/day4/src/main.rs +++ b/2023/day4/src/main.rs @@ -1,29 +1,64 @@ -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::iter::FromIterator; const FILE_STR: &'static str = include_str!("input.txt"); -#[derive(Default, Debug)] +#[derive(Debug, Default)] struct ScratchCard { winning: Vec, chosen: Vec, + chosen_winners: HashSet, } impl ScratchCard { fn new(winning: Vec, chosen: Vec) -> Self { - ScratchCard { winning, chosen } + ScratchCard { + winning, + chosen, + ..Self::default() + } + } + + fn find_chosen_winners(&mut self) { + self.winning + .iter() + .filter(|w| self.chosen.contains(w)) + .for_each(|cw| _ = self.chosen_winners.insert(*cw)); + } + + fn score(&mut self) -> usize { + self.find_chosen_winners(); + if self.chosen_winners.is_empty() { + return 0; + } + + let winner_count = self.chosen_winners.len() as u32; + usize::pow(2, winner_count - 1) } } -type GameMap = HashMap; +#[derive(Debug, Default)] +struct GameMap(HashMap); -/// Parse numbers from a line, separated/surrounded by whitespace -fn parse_num_str(s: &str) -> Vec { - s.split_ascii_whitespace() - .filter(|s| s.len() > 0) - .map(|s| s.trim()) - .map(|s| usize::from_str_radix(s, 10).unwrap()) - .collect::>() +impl GameMap { + fn parse(table: &str) -> Self { + Self(HashMap::from_iter( + table + .split('\n') + .filter(|s| s.len() > 0) + .map(parse_game_table_line), + )) + } + + fn find_all_chosen_winners(&mut self) { + self.0.iter_mut().for_each(|(_, sc)| { + sc.find_chosen_winners(); + }) + } + + fn get_score_sum(&mut self) -> usize { + self.0.iter_mut().map(|(_, sc)| sc.score()).sum() + } } fn parse_game_table_line(line: &str) -> (usize, ScratchCard) { @@ -35,18 +70,19 @@ fn parse_game_table_line(line: &str) -> (usize, ScratchCard) { (card_num, ScratchCard::new(nums[0].clone(), nums[1].clone())) } -fn parse_game_table(table: &str) -> GameMap { - HashMap::from_iter( - table - .split('\n') - .filter(|s| s.len() > 0) - .map(parse_game_table_line), - ) +/// Parse numbers from a line, separated/surrounded by whitespace +fn parse_num_str(s: &str) -> Vec { + s.split_ascii_whitespace() + .filter(|s| s.len() > 0) + .map(|s| s.trim()) + .map(|s| usize::from_str_radix(s, 10).unwrap()) + .collect::>() } fn part_one() { - let map = parse_game_table(FILE_STR); - println!("{:#?}", map); + let mut map = GameMap::parse(FILE_STR); + let sum = map.get_score_sum(); + println!("Part 1 Score Sum {}", sum); } fn main() { @@ -57,4 +93,11 @@ fn main() { mod tests { use super::*; const EXAMPLE_FILE_STR: &'static str = include_str!("example_input.txt"); + + #[test] + fn test_part1_example() { + let mut map = GameMap::parse(EXAMPLE_FILE_STR); + let actual = map.get_score_sum(); + assert_eq!(13, actual); + } }