Compare commits

..

2 commits

Author SHA1 Message Date
3c4e784d97
day 7 part 2 2023-12-07 16:17:58 +01:00
ca8d1c7708
day 7 part 1 2023-12-07 15:48:28 +01:00
2 changed files with 1180 additions and 0 deletions

1000
inputs/day7.txt Normal file

File diff suppressed because it is too large Load diff

180
src/bin/day7.rs Normal file
View file

@ -0,0 +1,180 @@
#![allow(clippy::no_effect)]
#![forbid(elided_lifetimes_in_paths, unsafe_code)]
use aoc23::read;
use chumsky::{prelude::*, text::int};
use std::{
collections::{BTreeSet, HashMap},
fmt::{self, Debug}
};
macro_rules! cards {
($($ident:ident = $char:literal),+) => {
#[derive(Clone, Copy, Eq, Hash, PartialEq, PartialOrd, Ord)]
enum Card { $($ident),+ }
impl Card {
fn all_cards() -> [Self; 0 $(+ { $char; 1 })+] {
[$(Self::$ident),+]
}
fn parser() -> impl Parser<char, Self, Error = Simple<char>> {
choice((
$(just($char).map(|_| Self::$ident)),+
))
}
}
impl Debug for Card {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
$(Self::$ident => write!(f, "{}", $char)),+
}
}
}
}
}
cards! {
Joker = '*',
Two = '2',
Three = '3',
Four = '4',
Five = '5',
Six = '6',
Seven = '7',
Eight = '8',
Nine = '9',
Ten = 'T',
Junior = 'J',
Queen = 'Q',
King = 'K',
Ass = 'A'
}
#[derive(Debug, Eq, PartialEq, PartialOrd, Ord)]
enum Type {
/// All distinct (e.g. `23456`).
HighCard,
/// One pair (e.g. `A23A4`).
OnePair,
/// Two pair (e.g. `23432`).
TwoPair,
/// Three of a kind (e.g. `TTT98`).
ThreeOfAKind,
/// Full house (e.g. `23332`).
FullHouse,
/// Four of a kind (e.g. `AA8AA`).
FourOfAKind,
/// Five of a kind (e.g. `AAAAA`).
FiveOfAKind
}
#[derive(Debug, Eq, PartialEq, PartialOrd, Ord)]
struct Hand {
ty: Type,
cards: [Card; 5],
bid: usize
}
impl Hand {
fn new(cards: [Card; 5], bid: usize) -> Self {
let mut counts: HashMap<Card, usize> = HashMap::new();
let mut jokers = 0;
for card in cards {
if card == Card::Joker {
jokers += 1;
} else {
*counts.entry(card).or_default() += 1;
}
}
match counts.values_mut().max() {
Some(max) => {
*max += jokers;
},
None => {
counts.insert(Card::Joker, jokers);
}
}
let ty = if counts.values().any(|c| *c >= 5) {
Type::FiveOfAKind
} else if counts.values().any(|c| *c >= 4) {
Type::FourOfAKind
} else if counts.values().any(|c| *c >= 3) {
if counts.values().filter(|c| **c >= 2).count() >= 2 {
Type::FullHouse
} else {
Type::ThreeOfAKind
}
} else {
let pairs = counts.values().filter(|c| **c >= 2).count();
match pairs {
0 => Type::HighCard,
1 => Type::OnePair,
_ => Type::TwoPair
}
};
Self { ty, cards, bid }
}
fn parser() -> impl Parser<char, Self, Error = Simple<char>> {
Card::parser()
.repeated()
.exactly(5)
.then_ignore(just(" "))
.then(int(10))
.map(|(cards, bid)| {
Self::new(cards.try_into().unwrap(), bid.parse().unwrap())
})
}
}
fn parser() -> impl Parser<char, Vec<Hand>, Error = Simple<char>> {
Hand::parser()
.then_ignore(just("\n"))
.repeated()
.then_ignore(end())
}
fn sum_hands<'a>(hands: impl IntoIterator<Item = &'a Hand>) -> usize {
hands
.into_iter()
.enumerate()
.map(|(i, hand)| (i + 1) * hand.bid)
.sum::<usize>()
}
fn main() -> anyhow::Result<()> {
let hands = read("inputs/day7.txt", parser())?;
// eprintln!("{hands:?}");
let sorted: BTreeSet<&Hand> = hands.iter().collect();
// eprintln!("{sorted:?}");
let sum = sum_hands(sorted);
println!("{sum}");
// assert_eq!(sum, 251106089);
let sorted: BTreeSet<Hand> = hands
.iter()
.map(|hand| {
let mut cards = hand.cards;
for card in &mut cards {
if *card == Card::Junior {
*card = Card::Joker;
}
}
let hand = Hand::new(cards, hand.bid);
// eprintln!("{hand:?}");
hand
})
.collect();
// eprintln!("{sorted:#?}");
let sum = sum_hands(&sorted);
println!("{sum}");
// assert!(sum > 249135400);
// assert!(sum < 249779500);
Ok(())
}