Complete 2023 day4 part 1

This commit is contained in:
Timothy Warren 2023-12-08 12:08:55 -05:00
parent 3a87c13750
commit c3773862a4

View File

@ -1,29 +1,64 @@
use std::collections::HashMap; use std::collections::{HashMap, HashSet};
use std::iter::FromIterator; use std::iter::FromIterator;
const FILE_STR: &'static str = include_str!("input.txt"); const FILE_STR: &'static str = include_str!("input.txt");
#[derive(Default, Debug)] #[derive(Debug, Default)]
struct ScratchCard { struct ScratchCard {
winning: Vec<usize>, winning: Vec<usize>,
chosen: Vec<usize>, chosen: Vec<usize>,
chosen_winners: HashSet<usize>,
} }
impl ScratchCard { impl ScratchCard {
fn new(winning: Vec<usize>, chosen: Vec<usize>) -> Self { fn new(winning: Vec<usize>, chosen: Vec<usize>) -> 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<usize, ScratchCard>; #[derive(Debug, Default)]
struct GameMap(HashMap<usize, ScratchCard>);
/// Parse numbers from a line, separated/surrounded by whitespace impl GameMap {
fn parse_num_str(s: &str) -> Vec<usize> { fn parse(table: &str) -> Self {
s.split_ascii_whitespace() Self(HashMap::from_iter(
.filter(|s| s.len() > 0) table
.map(|s| s.trim()) .split('\n')
.map(|s| usize::from_str_radix(s, 10).unwrap()) .filter(|s| s.len() > 0)
.collect::<Vec<usize>>() .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) { 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())) (card_num, ScratchCard::new(nums[0].clone(), nums[1].clone()))
} }
fn parse_game_table(table: &str) -> GameMap { /// Parse numbers from a line, separated/surrounded by whitespace
HashMap::from_iter( fn parse_num_str(s: &str) -> Vec<usize> {
table s.split_ascii_whitespace()
.split('\n') .filter(|s| s.len() > 0)
.filter(|s| s.len() > 0) .map(|s| s.trim())
.map(parse_game_table_line), .map(|s| usize::from_str_radix(s, 10).unwrap())
) .collect::<Vec<usize>>()
} }
fn part_one() { fn part_one() {
let map = parse_game_table(FILE_STR); let mut map = GameMap::parse(FILE_STR);
println!("{:#?}", map); let sum = map.get_score_sum();
println!("Part 1 Score Sum {}", sum);
} }
fn main() { fn main() {
@ -57,4 +93,11 @@ fn main() {
mod tests { mod tests {
use super::*; use super::*;
const EXAMPLE_FILE_STR: &'static str = include_str!("example_input.txt"); 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);
}
} }