Solve day 7
This commit is contained in:
parent
c5470de9ea
commit
f16fae23ab
2 changed files with 177 additions and 0 deletions
5
input/07-test
Normal file
5
input/07-test
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
32T3K 765
|
||||||
|
T55J5 684
|
||||||
|
KK677 28
|
||||||
|
KTJJT 220
|
||||||
|
QQQJA 483
|
172
src/bin/07.rs
Normal file
172
src/bin/07.rs
Normal 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))
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue