refactor for yearly
This commit is contained in:
parent
da00eb3606
commit
dddda24957
57 changed files with 3 additions and 0 deletions
207
2023/src/bin/day07.rs
Normal file
207
2023/src/bin/day07.rs
Normal file
|
@ -0,0 +1,207 @@
|
|||
use aoc23::prelude::*;
|
||||
use derive_builder::Builder;
|
||||
use itertools::Itertools;
|
||||
use std::{cmp::Ordering, str::FromStr, time::Instant};
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)]
|
||||
enum Strength {
|
||||
HighCard,
|
||||
OnePair,
|
||||
TwoPair,
|
||||
ThreeOfAKind,
|
||||
FullHouse,
|
||||
FourOfAKind,
|
||||
FiveOfAKind,
|
||||
}
|
||||
|
||||
impl Strength {
|
||||
#[cfg(feature = "part2")]
|
||||
fn for_hand(hand: &Hand) -> Self {
|
||||
let mut counts = [0; 15];
|
||||
let mut jokers = 0;
|
||||
for card in hand.cards.iter() {
|
||||
if card == &1 {
|
||||
jokers += 1;
|
||||
} else {
|
||||
counts[*card as usize - 2] += 1;
|
||||
}
|
||||
}
|
||||
let mut strength = counts
|
||||
.iter()
|
||||
.fold(Strength::HighCard, |strength, &count| match count {
|
||||
5 => Strength::FiveOfAKind,
|
||||
4 => Strength::FourOfAKind,
|
||||
3 => match strength {
|
||||
Strength::TwoPair => Strength::FullHouse,
|
||||
Strength::OnePair => Strength::FullHouse,
|
||||
_ => Strength::ThreeOfAKind,
|
||||
},
|
||||
2 => match strength {
|
||||
Strength::ThreeOfAKind => Strength::FullHouse,
|
||||
Strength::OnePair => Strength::TwoPair,
|
||||
_ => Strength::OnePair,
|
||||
},
|
||||
_ => strength,
|
||||
});
|
||||
while jokers > 0 {
|
||||
strength = match strength {
|
||||
Strength::HighCard => Strength::OnePair,
|
||||
Strength::OnePair => Strength::ThreeOfAKind,
|
||||
Strength::TwoPair => Strength::FullHouse,
|
||||
Strength::ThreeOfAKind => Strength::FourOfAKind,
|
||||
Strength::FullHouse => Strength::FourOfAKind,
|
||||
Strength::FourOfAKind => Strength::FiveOfAKind,
|
||||
Strength::FiveOfAKind => Strength::FiveOfAKind,
|
||||
};
|
||||
jokers -= 1;
|
||||
}
|
||||
strength
|
||||
}
|
||||
|
||||
#[cfg(feature = "part1")]
|
||||
fn for_hand(hand: &Hand) -> Self {
|
||||
let mut counts = [0; 15];
|
||||
for card in hand.cards.iter() {
|
||||
counts[*card as usize - 2] += 1;
|
||||
}
|
||||
counts
|
||||
.iter()
|
||||
.fold(Strength::HighCard, |strength, &count| match count {
|
||||
5 => Strength::FiveOfAKind,
|
||||
4 => Strength::FourOfAKind,
|
||||
3 => match strength {
|
||||
Strength::TwoPair => Strength::FullHouse,
|
||||
Strength::OnePair => Strength::FullHouse,
|
||||
_ => Strength::ThreeOfAKind,
|
||||
},
|
||||
2 => match strength {
|
||||
Strength::ThreeOfAKind => Strength::FullHouse,
|
||||
Strength::OnePair => Strength::TwoPair,
|
||||
_ => Strength::OnePair,
|
||||
},
|
||||
_ => strength,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Builder, Clone, PartialEq, Eq)]
|
||||
struct Hand {
|
||||
cards: Vec<u32>,
|
||||
bid: usize,
|
||||
}
|
||||
|
||||
impl Ord for Hand {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
let self_strength = Strength::for_hand(self);
|
||||
let other_strength = Strength::for_hand(other);
|
||||
match self_strength.cmp(&other_strength) {
|
||||
Ordering::Equal => self
|
||||
.cards
|
||||
.iter()
|
||||
.zip(other.cards.iter())
|
||||
.map(|(s, o)| s.cmp(o))
|
||||
.skip_while(|ord| matches!(ord, Ordering::Equal))
|
||||
.next()
|
||||
.unwrap_or(Ordering::Equal),
|
||||
Ordering::Less => Ordering::Less,
|
||||
Ordering::Greater => Ordering::Greater,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Hand {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Hand {
|
||||
type Err = BoxE;
|
||||
|
||||
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
||||
let mut splits = s.trim().split_whitespace();
|
||||
Ok(HandBuilder::default()
|
||||
.cards(
|
||||
splits
|
||||
.next()
|
||||
.unwrap()
|
||||
.chars()
|
||||
.map(|c| {
|
||||
if let Some(digit) = c.to_digit(10) {
|
||||
digit
|
||||
} else {
|
||||
match c {
|
||||
#[cfg(feature = "part1")]
|
||||
'A' => 14,
|
||||
#[cfg(feature = "part2")]
|
||||
'A' => 13,
|
||||
#[cfg(feature = "part1")]
|
||||
'K' => 13,
|
||||
#[cfg(feature = "part2")]
|
||||
'K' => 12,
|
||||
#[cfg(feature = "part1")]
|
||||
'Q' => 12,
|
||||
#[cfg(feature = "part2")]
|
||||
'Q' => 11,
|
||||
#[cfg(feature = "part1")]
|
||||
'J' => 11,
|
||||
#[cfg(feature = "part2")]
|
||||
'J' => 1,
|
||||
'T' => 10,
|
||||
_ => panic!("invalid card: {}", c),
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
.bid(splits.next().unwrap().parse()?)
|
||||
.build()?)
|
||||
}
|
||||
}
|
||||
|
||||
fn calculate(input: String) -> Result<usize> {
|
||||
let start = Instant::now();
|
||||
let answer = input
|
||||
.lines()
|
||||
.map(|line| line.parse::<Hand>().unwrap())
|
||||
.sorted()
|
||||
.enumerate()
|
||||
.map(|(idx, hand)| hand.bid * (idx + 1))
|
||||
.sum();
|
||||
let algo_time = start.elapsed();
|
||||
println!("Day {DAY}: {answer}");
|
||||
println!("\t{algo_time:?}");
|
||||
Ok(answer)
|
||||
}
|
||||
|
||||
// TODO come back and revise for a faster solution
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
println!("Day {DAY}");
|
||||
println!("=====");
|
||||
let input = utils::aoc::get_puzzle_input(DAY).await?;
|
||||
calculate(input.clone())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
static DAY: u8 = 7;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
static DATA: &'static str = "32T3K 765
|
||||
T55J5 684
|
||||
KK677 28
|
||||
KTJJT 220
|
||||
QQQJA 483";
|
||||
|
||||
#[test]
|
||||
fn test() -> Result<()> {
|
||||
#[cfg(feature = "part1")]
|
||||
assert_eq!(calculate(DATA.to_owned())?, 6440);
|
||||
#[cfg(feature = "part2")]
|
||||
assert_eq!(calculate(DATA.to_owned())?, 5905);
|
||||
Ok(())
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue