diff --git a/2023/day-6/src/part1.rs b/2023/day-6/src/part1.rs index 1948cbd..9b28afd 100644 --- a/2023/day-6/src/part1.rs +++ b/2023/day-6/src/part1.rs @@ -44,7 +44,7 @@ fn parse_input(input: &str) -> IResult<&str, Vec<(u64, u64)>> { input, time.iter() .interleave(distance.iter()) - .map(|x| *x) + .copied() .tuples() .collect(), )) diff --git a/2023/day-6/src/part2.rs b/2023/day-6/src/part2.rs index 3cd2c29..919a56b 100644 --- a/2023/day-6/src/part2.rs +++ b/2023/day-6/src/part2.rs @@ -36,13 +36,13 @@ fn parse_input(input: &str) -> IResult<&str, (u64, u64)> { )(input)?; let distance = distance .iter() - .map(|x| x.to_string()) + .map(ToString::to_string) .join("") .parse::() .expect("is a number"); let time = time .iter() - .map(|x| x.to_string()) + .map(ToString::to_string) .join("") .parse::() .expect("is a number"); diff --git a/2023/day-7/src/part1.rs b/2023/day-7/src/part1.rs index d56d99d..5532a52 100644 --- a/2023/day-7/src/part1.rs +++ b/2023/day-7/src/part1.rs @@ -70,13 +70,13 @@ impl From<&Card> for &u32 { #[derive(Debug, Eq, PartialEq, Ord, PartialOrd)] enum HandType { - FiveOfAKind, - FourOfAKind, - FullHouse, - ThreeOfAKind, - TwoPair, - OnePair, HighCard, + OnePair, + TwoPair, + ThreeOfAKind, + FullHouse, + FourOfAKind, + FiveOfAKind, } impl From<&Hand> for HandType { @@ -105,16 +105,21 @@ impl From<&Hand> for HandType { } } -#[derive(Debug, Eq, PartialEq, Ord)] +#[derive(Debug, Eq, PartialEq)] struct Hand { pub cards: [Card; 5], pub bet: u32, } impl PartialOrd for Hand { fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} +impl Ord for Hand { + fn cmp(&self, other: &Self) -> Ordering { let a = HandType::from(self); let b = HandType::from(other); - let c = b.cmp(&a); + let c = a.cmp(&b); match c { Ordering::Equal => self .cards @@ -122,23 +127,22 @@ impl PartialOrd for Hand { .interleave(other.cards.iter()) .tuples::<(_, _)>() .find_map(|(a, b)| { - if b.cmp(a).is_ne() { - Some(a.cmp(b)) - } else { - None + match a.cmp(b) { + Ordering::Equal => None, + x => Some(x) } - }), - x => Some(x), + }).unwrap_or(Ordering::Equal), + x => x, } } } #[must_use] -pub fn part1(_input: &str) -> String { - let (_, mut hands) = parse_input(_input).expect("always valid input"); +pub fn part1(input: &str) -> String { + let (_, mut hands) = parse_input(input).expect("always valid input"); hands.sort(); - dbg!(hands) + hands .iter() .enumerate() .map(|(i, hand)| (i + 1) * hand.bet as usize) @@ -178,4 +182,3 @@ QQQJA 483"; assert_eq!(result, "6440".to_string()); } } - diff --git a/2023/day-7/src/part2.rs b/2023/day-7/src/part2.rs index 8f15571..26c688a 100644 --- a/2023/day-7/src/part2.rs +++ b/2023/day-7/src/part2.rs @@ -1,20 +1,196 @@ #![warn(clippy::all, clippy::pedantic)] +use itertools::Itertools; +use nom::{character::complete, multi::separated_list1, sequence::separated_pair, IResult}; +use std::{ + cmp::{Ord, Ordering, PartialOrd}, + collections::BTreeMap, + str::FromStr, +}; + +#[derive(Debug)] +struct Day1Part2Error; + +#[derive(Debug, Ord, Eq, PartialEq, PartialOrd)] +enum Card { + Joker = 1, + Two, + Three, + Four, + Five, + Six, + Seven, + Eight, + Nine, + Ten, + Queen, + King, + Ace, +} +impl FromStr for Card { + type Err = Day1Part2Error; + fn from_str(input: &str) -> Result { + match input { + "2" => Ok(Self::Two), + "3" => Ok(Self::Three), + "4" => Ok(Self::Four), + "5" => Ok(Self::Five), + "6" => Ok(Self::Six), + "7" => Ok(Self::Seven), + "8" => Ok(Self::Eight), + "9" => Ok(Self::Nine), + "T" => Ok(Self::Ten), + "J" => Ok(Self::Joker), + "Q" => Ok(Self::Queen), + "K" => Ok(Self::King), + "A" => Ok(Self::Ace), + _ => Err(Day1Part2Error), + } + } +} + +impl From<&Card> for &u32 { + fn from(value: &Card) -> Self { + match value { + Card::Two => &2, + Card::Three => &3, + Card::Four => &4, + Card::Five => &5, + Card::Six => &6, + Card::Seven => &7, + Card::Eight => &8, + Card::Nine => &9, + Card::Ten => &10, + Card::Joker => &1, + Card::Queen => &12, + Card::King => &13, + Card::Ace => &14, + } + } +} + +#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)] +enum HandType { + HighCard, + OnePair, + TwoPair, + ThreeOfAKind, + FullHouse, + FourOfAKind, + FiveOfAKind, +} + +impl From<&Hand> for HandType { + fn from(value: &Hand) -> Self { + let mut map = value.cards.iter().fold(BTreeMap::new(), |mut acc, card| { + if let Some(c) = acc.get_mut(card) { + *c += 1; + } else { + acc.insert(card, 1); + } + acc + }); + let jokers = map.remove(&Card::Joker).unwrap_or(0); + match map + .iter() + .sorted_by(|a, b| b.1.cmp(a.1)) + .collect::>()[..] + { + [(_, x),..] if jokers + x == 5 => Self::FiveOfAKind, + [(_, x), ..] if jokers + x == 4 => Self::FourOfAKind, + [(_, 3), (_, 2)] => Self::FullHouse, + [(_, 2), (_, 2)] if jokers == 1 => Self::FullHouse, + [(_, x), ..] if jokers + x == 3 => Self::ThreeOfAKind, + [(_, 2), (_, 2), ..] => Self::TwoPair, + [(_, x), ..] if jokers + x == 2 => Self::OnePair, + _ => Self::HighCard, + } + } +} + +#[derive(Debug, Eq, PartialEq)] +struct Hand { + pub cards: [Card; 5], + pub bet: u32, +} +impl PartialOrd for Hand { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} +impl Ord for Hand { + fn cmp(&self, other: &Self) -> Ordering { + let a = HandType::from(self); + let b = HandType::from(other); + let c = a.cmp(&b); + match c { + Ordering::Equal => self + .cards + .iter() + .interleave(other.cards.iter()) + .tuples::<(_, _)>() + .find_map(|(a, b)| { + match a.cmp(b) { + Ordering::Equal => None, + x => Some(x) + } + }).unwrap_or(Ordering::Equal), + x => x, + } + } +} #[must_use] -pub fn part2 (_input: &str) -> String { - "Not Finished".to_string() +pub fn part2(input: &str) -> String { + let (_, mut hands) = parse_input(input).expect("always valid input"); + hands.sort(); + + hands + .iter() + .enumerate() + .map(|(i, hand)| (i + 1) * hand.bet as usize) + .sum::() + .to_string() +} + +fn parse_hand(input: &str) -> IResult<&str, Hand> { + let (input, (cards, bet)) = + separated_pair(complete::alphanumeric1, complete::space1, complete::u32)(input)?; + let cards = cards + .chars() + .filter_map(|c| c.to_string().parse().ok()) + .collect::>() + .try_into() + .expect("should work"); + Ok((input, Hand { cards, bet })) +} + +fn parse_input(input: &str) -> IResult<&str, Vec> { + separated_list1(complete::line_ending, parse_hand)(input) } #[cfg(test)] mod test { use super::*; - const INPUT: &str = ""; + #[test] + fn qtest() { + let a_str = "JKKK2 9"; + let b_str = "QQQQ2 8"; + let (_, a_hand) = parse_hand(a_str).expect("shoould parse a"); + let (_, b_hand) = parse_hand(b_str).expect("should parse b"); + let c = a_hand.cmp(&b_hand); + assert_eq!(c, Ordering::Less); + } + + const INPUT: &str = "32T3K 765 +T55J5 684 +KK677 28 +KTJJT 220 +QQQJA 483"; #[test] fn part2_works() { let result = part2(INPUT); - assert_eq!(result, "Not Finished".to_string()); + assert_eq!(result, "5905".to_string()); } } -