day 4 finished

This commit is contained in:
Dylan Thies
2023-12-04 17:33:01 -05:00
parent a61df8b05d
commit 1bdc3e19fa
2 changed files with 165 additions and 41 deletions

View File

@@ -1,68 +1,90 @@
#![warn(clippy::all, clippy::pedantic)]
use nom::{ bytes::complete::tag,
use nom::{
bytes::complete::tag,
character::complete,
multi::{fold_many1, separated_list1},
sequence::{preceded, separated_pair, tuple},
IResult,
multi::separated_list1,
sequence::{preceded, separated_pair}};
};
use std::collections::HashSet;
struct Card {
pub _id: u8,
pub game_numbers: Vec<u8>,
pub my_numbers: Vec<u8>,
pub game_numbers: HashSet<u8>,
pub my_numbers: HashSet<u8>,
}
impl Card {
fn get_score(&self) -> Option<usize>{
let count = self.my_numbers.iter().filter(|x| self.game_numbers.contains(x)).count();
fn get_win_count(&self) -> usize {
self.my_numbers.intersection(&self.game_numbers).count()
}
fn get_score(&self) -> Option<usize> {
let count = self.get_win_count();
if count == 0 {
None
} else {
Some(2_usize.pow(count as u32- 1))
Some(2_usize.pow(u32::try_from(count).expect("shouldn't have a lot of cards") - 1))
}
}
}
/// day 4 part 1 of aoc 2023
///
/// # Arguments
/// - input the input for today's puzzle
///
/// # Panics
/// panics whne it cannot parse the input OR when ever the number of game numbers is greater than
/// usize
#[must_use]
pub fn part1(input: &str) -> String {
let (_, cards) = parse_input(input).expect("there should be input");
cards.iter().filter_map(Card::get_score).sum::<usize>().to_string()
cards
.iter()
.filter_map(Card::get_score)
.sum::<usize>()
.to_string()
}
fn parse_num_list (input: &str) -> IResult<&str, Vec<u8>> {
separated_list1(complete::space1, complete::u8)(input)
fn parse_num_list(input: &str) -> IResult<&str, HashSet<u8>> {
fold_many1(
tuple((complete::u8, complete::space0)),
HashSet::new,
|mut acc, (x, _)| {
acc.insert(x);
acc
},
)(input)
}
fn parse_numbers(input: &str) -> IResult<&str, (Vec<u8>, Vec<u8>)> {
separated_pair(parse_num_list, barspace, parse_num_list)(input)
}
fn barspace(input: &str) -> IResult<&str, () > {
let (i, _) = complete::space1(input)?;
let (i,_) = tag("|")(i)?;
let (i, _) = complete::space1(i)?;
Ok((i, ()))
}
fn colonspace(input: &str) -> IResult<&str, () > {
let (i,_) = tag(":")(input)?;
let (i, _) = complete::space1(i)?;
Ok((i, ()))
}
fn cardspace(input: &str) -> IResult<&str, () > {
let (input, _) = tag("Card")(input)?;
let (input, _) = complete::space1(input)?;
Ok((input, ()))
fn parse_numbers(input: &str) -> IResult<&str, (HashSet<u8>, HashSet<u8>)> {
separated_pair(
parse_num_list,
tuple((tag("|"), complete::space1)),
parse_num_list,
)(input)
}
fn parse_card(input: &str) -> IResult<&str, Card> {
let (input, (id, (my_numbers, game_numbers))) = separated_pair(preceded(cardspace, complete::u8), colonspace, parse_numbers )(input)?;
let (input, (id, (my_numbers, game_numbers))) = separated_pair(
preceded(tuple((tag("Card"), complete::space1)), complete::u8),
tuple((tag(":"), complete::space1)),
parse_numbers,
)(input)?;
Ok((input, Card{_id:id, my_numbers, game_numbers}))
Ok((
input,
Card {
_id: id,
game_numbers,
my_numbers,
},
))
}
fn parse_input(input:&str) -> IResult<&str, Vec<Card>> {
separated_list1(complete::newline, parse_card)(input)
fn parse_input(input: &str) -> IResult<&str, Vec<Card>> {
separated_list1(complete::line_ending, parse_card)(input)
}
#[cfg(test)]

View File

@@ -1,19 +1,121 @@
#![warn(clippy::all, clippy::pedantic)]
pub fn part2 (_input: &str) -> String {
"Not Finished".to_string()
use nom::{
bytes::complete::tag,
character::complete,
combinator::map,
multi::{fold_many1, separated_list1},
sequence::{preceded, separated_pair, tuple},
IResult,
};
use std::collections::{BTreeMap, HashSet};
struct Card {
pub id: usize,
pub game_numbers: HashSet<u8>,
pub my_numbers: HashSet<u8>,
}
impl Card {
fn get_win_count(&self) -> usize {
self.my_numbers.intersection(&self.game_numbers).count()
}
}
/// day 4 part 1 of aoc 2023
///
/// # Arguments
/// - input the input for today's puzzle
///
/// # Panics
/// panics whne it cannot parse the input OR when ever the number of game numbers is greater than
/// usize
#[must_use]
pub fn part2(input: &str) -> String {
let (_, cards) = parse_input(input).expect("there should be input");
let mut cards_had = BTreeMap::new();
for card in cards {
if let Some(x) = cards_had.get_mut(&card.id) {
*x += 1;
} else {
cards_had.insert(card.id, 1);
}
let next_id = card.id + 1;
let last_winner = card.id + card.get_win_count();
//println!("{} - {next_id} {last_winner}", card.id);
if last_winner < next_id {
continue;
}
let card_count = *cards_had.get(&card.id).expect("already should have cards");
for id in next_id..=last_winner {
if let Some(x) = cards_had.get_mut(&id) {
*x += card_count;
} else {
cards_had.insert(id, card_count);
}
}
}
//println!("{cards_had:#?}");
cards_had.values().sum::<usize>().to_string()
}
fn parse_num_list(input: &str) -> IResult<&str, HashSet<u8>> {
fold_many1(
tuple((complete::u8, complete::space0)),
HashSet::new,
|mut acc, (x, _)| {
acc.insert(x);
acc
},
)(input)
}
fn parse_numbers(input: &str) -> IResult<&str, (HashSet<u8>, HashSet<u8>)> {
separated_pair(
parse_num_list,
tuple((tag("|"), complete::space1)),
parse_num_list,
)(input)
}
fn parse_card(input: &str) -> IResult<&str, Card> {
let (input, (id, (my_numbers, game_numbers))) = separated_pair(
preceded(
tuple((tag("Card"), complete::space1)),
map(complete::u8, usize::from),
),
tuple((tag(":"), complete::space1)),
parse_numbers,
)(input)?;
Ok((
input,
Card {
id,
game_numbers,
my_numbers,
},
))
}
fn parse_input(input: &str) -> IResult<&str, Vec<Card>> {
separated_list1(complete::line_ending, parse_card)(input)
}
#[cfg(test)]
mod test {
use super::*;
const INPUT: &str = "";
const INPUT: &str = "Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53
Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19
Card 3: 1 21 53 59 44 | 69 82 63 72 16 21 14 1
Card 4: 41 92 73 84 69 | 59 84 76 51 58 5 54 83
Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36
Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 11";
#[test]
fn part2_works() {
let result = part2(INPUT);
assert_eq!(result, "Not Finished".to_string());
assert_eq!(result, "30".to_string());
}
}