1
0
Fork 0

Solve day 7

This commit is contained in:
Lars Martens 2023-12-07 18:02:33 +01:00
parent c5470de9ea
commit f16fae23ab
Signed by: haselkern
GPG key ID: B5CF1F363C179AD4
2 changed files with 177 additions and 0 deletions

5
input/07-test Normal file
View file

@ -0,0 +1,5 @@
32T3K 765
T55J5 684
KK677 28
KTJJT 220
QQQJA 483

172
src/bin/07.rs Normal file
View file

@ -0,0 +1,172 @@
use itertools::Itertools;
use std::cmp::Ordering;
const INPUT: &str = include_str!("../../input/07");
const TEST_INPUT: &str = include_str!("../../input/07-test");
fn main() {
assert_eq!(part1(TEST_INPUT), 6440, "Part 1");
println!("Part 1: {}", part1(INPUT));
assert_eq!(part2(TEST_INPUT), 5905, "Part 2");
println!("Part 2: {}", part2(INPUT));
}
fn part1(input: &str) -> usize {
solve(input, false)
}
fn part2(input: &str) -> usize {
solve(input, true)
}
fn solve(input: &str, jokers_are_wildcards: bool) -> usize {
parse(input, jokers_are_wildcards)
.sorted()
.enumerate()
.map(|(rank0, hand)| (rank0 + 1) * hand.bid)
.sum()
}
#[derive(Eq, Debug)]
struct Hand {
cards: [Card; 5],
bid: usize,
}
impl Hand {
fn kind(&self) -> HandKind {
let counted = self
.cards
.iter()
.filter(|card| !card.is_wildcard())
.counts_by(|card| card.symbol);
let wildcards = self.cards.iter().filter(|card| card.is_wildcard()).count();
let same_cards = counted.values().copied().max().unwrap_or(0);
let pairs = counted.values().copied().filter(|&c| c == 2).count();
if same_cards == 5
|| same_cards == 4 && wildcards == 1
|| same_cards == 3 && wildcards == 2
|| pairs == 1 && wildcards == 3
|| wildcards >= 4
{
HandKind::Five
} else if same_cards == 4
|| same_cards == 3 && wildcards == 1
|| pairs == 1 && wildcards == 2
|| wildcards >= 3
{
HandKind::Four
} else if same_cards == 3 && pairs == 1
|| pairs == 2 && wildcards == 1
|| pairs == 1 && wildcards == 2
{
HandKind::FullHouse
} else if same_cards == 3 || pairs == 1 && wildcards == 1 || wildcards == 2 {
HandKind::Three
} else if pairs == 2 || wildcards == 2 {
HandKind::TwoPair
} else if pairs == 1 || wildcards == 1 {
HandKind::OnePair
} else {
HandKind::HighCard
}
}
fn parse(line: &str, jokers_are_wildcards: bool) -> Self {
let (cards, bid) = line.split_once(' ').unwrap();
let cards = cards
.chars()
.map(|symbol| Card {
symbol,
jokers_are_wildcards,
})
.collect_vec()
.try_into()
.unwrap();
let bid = bid.parse().unwrap();
Self { cards, bid }
}
}
impl Ord for Hand {
fn cmp(&self, other: &Self) -> Ordering {
match self.kind().cmp(&other.kind()) {
Ordering::Less => Ordering::Less,
Ordering::Greater => Ordering::Greater,
Ordering::Equal => self.cards.iter().cmp(&other.cards),
}
}
}
impl PartialOrd for Hand {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl PartialEq<Self> for Hand {
fn eq(&self, other: &Self) -> bool {
self.cmp(other).is_eq()
}
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
enum HandKind {
HighCard,
OnePair,
TwoPair,
Three,
FullHouse,
Four,
Five,
}
#[derive(PartialEq, Eq, Debug, Copy, Clone)]
struct Card {
symbol: char,
jokers_are_wildcards: bool,
}
impl Card {
fn is_wildcard(&self) -> bool {
self.jokers_are_wildcards && self.symbol == 'J'
}
}
impl Ord for Card {
fn cmp(&self, other: &Self) -> Ordering {
let order = |card: &Card| match card.symbol {
'A' => 14,
'K' => 13,
'Q' => 12,
'J' if card.jokers_are_wildcards => 1,
'J' => 11,
'T' => 10,
'9' => 9,
'8' => 8,
'7' => 7,
'6' => 6,
'5' => 5,
'4' => 4,
'3' => 3,
'2' => 2,
other => panic!("unknown card symbol '{other}'"),
};
order(self).cmp(&order(other))
}
}
impl PartialOrd for Card {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
fn parse(input: &str, jokers_are_wildcards: bool) -> impl Iterator<Item = Hand> + '_ {
input
.lines()
.map(move |l| Hand::parse(l, jokers_are_wildcards))
}