day(07): add solution
Signed-off-by: Matej Focko <mfocko@redhat.com>
This commit is contained in:
parent
19c94a7c46
commit
44624770cd
2 changed files with 220 additions and 0 deletions
5
samples/day07.txt
Normal file
5
samples/day07.txt
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
32T3K 765
|
||||||
|
T55J5 684
|
||||||
|
KK677 28
|
||||||
|
KTJJT 220
|
||||||
|
QQQJA 483
|
215
src/bin/day07.rs
Normal file
215
src/bin/day07.rs
Normal file
|
@ -0,0 +1,215 @@
|
||||||
|
use std::{
|
||||||
|
cmp::{self, Reverse},
|
||||||
|
str::FromStr,
|
||||||
|
};
|
||||||
|
|
||||||
|
use aoc_2023::*;
|
||||||
|
|
||||||
|
type Output1 = i32;
|
||||||
|
type Output2 = Output1;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
enum HandType {
|
||||||
|
HighCard,
|
||||||
|
OnePair,
|
||||||
|
TwoPair,
|
||||||
|
ThreeOfAKind,
|
||||||
|
FullHouse,
|
||||||
|
FourOfAKind,
|
||||||
|
FiveOfAKind,
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref CARDS: Vec<char> =
|
||||||
|
vec!['2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A',];
|
||||||
|
static ref CARDS_2: Vec<char> =
|
||||||
|
vec!['J', '2', '3', '4', '5', '6', '7', '8', '9', 'T', 'Q', 'K', 'A',];
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
struct Hand {
|
||||||
|
cards: Vec<char>,
|
||||||
|
bid: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Hand {
|
||||||
|
type Err = &'static str;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
let parts = s.split_ascii_whitespace().collect_vec();
|
||||||
|
|
||||||
|
let cards = parts[0].chars().collect_vec();
|
||||||
|
let bid = parts[1].parse().unwrap();
|
||||||
|
|
||||||
|
Ok(Self { cards, bid })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for Hand {
|
||||||
|
fn cmp(&self, other: &Self) -> cmp::Ordering {
|
||||||
|
let my_type = self.hand_type();
|
||||||
|
let other_type = other.hand_type();
|
||||||
|
|
||||||
|
match my_type.partial_cmp(&other_type) {
|
||||||
|
Some(cmp::Ordering::Equal) => {}
|
||||||
|
Some(ord) => return ord,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (my, other) in self.cards.iter().zip(other.cards.iter()) {
|
||||||
|
let l = CARDS
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.find_map(|(i, c)| if c == my { Some(i) } else { None })
|
||||||
|
.unwrap();
|
||||||
|
let r = CARDS
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.find_map(|(i, c)| if c == other { Some(i) } else { None })
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
match l.partial_cmp(&r) {
|
||||||
|
Some(cmp::Ordering::Equal) => {}
|
||||||
|
Some(ord) => return ord,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cmp::Ordering::Equal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialOrd for Hand {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hand {
|
||||||
|
fn hand_type(&self) -> HandType {
|
||||||
|
let freqs = self.cards.iter().counts();
|
||||||
|
|
||||||
|
let mut pairs = 0;
|
||||||
|
let mut triplets = 0;
|
||||||
|
|
||||||
|
for &value in freqs.values() {
|
||||||
|
match value {
|
||||||
|
5 => {
|
||||||
|
return HandType::FiveOfAKind;
|
||||||
|
}
|
||||||
|
4 => {
|
||||||
|
return HandType::FourOfAKind;
|
||||||
|
}
|
||||||
|
3 => {
|
||||||
|
triplets += 1;
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
pairs += 1;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if pairs == 1 && triplets == 1 {
|
||||||
|
return HandType::FullHouse;
|
||||||
|
}
|
||||||
|
|
||||||
|
if triplets > 0 {
|
||||||
|
return HandType::ThreeOfAKind;
|
||||||
|
}
|
||||||
|
|
||||||
|
match pairs {
|
||||||
|
2 => HandType::TwoPair,
|
||||||
|
1 => HandType::OnePair,
|
||||||
|
_ => HandType::HighCard,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hand_type_with_joker(&self) -> HandType {
|
||||||
|
let mut freqs = self.cards.iter().counts();
|
||||||
|
let jokers = *freqs.get(&'J').unwrap_or(&0);
|
||||||
|
|
||||||
|
freqs.remove(&'J');
|
||||||
|
let mut freqs = freqs.values().cloned().collect_vec();
|
||||||
|
freqs.sort_by_key(|&c| Reverse(c));
|
||||||
|
|
||||||
|
if jokers == 5 || freqs[0] + jokers == 5 {
|
||||||
|
HandType::FiveOfAKind
|
||||||
|
} else if freqs[0] + jokers == 4 {
|
||||||
|
HandType::FourOfAKind
|
||||||
|
} else if freqs[0] + jokers == 3 && freqs[1] == 2 {
|
||||||
|
HandType::FullHouse
|
||||||
|
} else if freqs[0] + jokers == 3 {
|
||||||
|
HandType::ThreeOfAKind
|
||||||
|
} else if freqs[0] == 2 && freqs[1] == 2 {
|
||||||
|
HandType::TwoPair
|
||||||
|
} else if freqs[0] + jokers == 2 {
|
||||||
|
HandType::OnePair
|
||||||
|
} else {
|
||||||
|
HandType::HighCard
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Day07 {
|
||||||
|
hands: Vec<Hand>,
|
||||||
|
}
|
||||||
|
impl Solution<Output1, Output2> for Day07 {
|
||||||
|
fn new<P: AsRef<Path>>(pathname: P) -> Self {
|
||||||
|
let hands = file_to_structs(pathname);
|
||||||
|
|
||||||
|
Self { hands }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part_1(&mut self) -> Output1 {
|
||||||
|
self.hands.sort();
|
||||||
|
self.hands
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(r, h)| (r as i32 + 1) * h.bid)
|
||||||
|
.sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part_2(&mut self) -> Output2 {
|
||||||
|
self.hands.sort_by(|x, y| {
|
||||||
|
let my_type = x.hand_type_with_joker();
|
||||||
|
let other_type = y.hand_type_with_joker();
|
||||||
|
|
||||||
|
match my_type.partial_cmp(&other_type) {
|
||||||
|
Some(core::cmp::Ordering::Equal) => {}
|
||||||
|
ord => return ord.unwrap(),
|
||||||
|
}
|
||||||
|
|
||||||
|
for (my, other) in x.cards.iter().zip(y.cards.iter()) {
|
||||||
|
let l = CARDS_2
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.find_map(|(i, c)| if c == my { Some(i) } else { None })
|
||||||
|
.unwrap();
|
||||||
|
let r = CARDS_2
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.find_map(|(i, c)| if c == other { Some(i) } else { None })
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
match l.partial_cmp(&r) {
|
||||||
|
Some(core::cmp::Ordering::Equal) => {}
|
||||||
|
ord => return ord.unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unreachable!()
|
||||||
|
});
|
||||||
|
self.hands
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(r, h)| (r as i32 + 1) * h.bid)
|
||||||
|
.sum()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<()> {
|
||||||
|
Day07::main()
|
||||||
|
}
|
||||||
|
|
||||||
|
test_sample!(day_07, Day07, 6440, 5905);
|
Loading…
Reference in a new issue