AoC 2023 day 7
The snippet can be accessed without any authentication.
Authored by
s91149
main.rs 3.78 KiB
use std::{cmp::Ordering, collections::HashMap};
fn main() {
let mut hands: Vec<Hand> = std::fs::read_to_string("../inputs/input.txt")
.unwrap()
.lines()
.map(|line| {
let split: Vec<&str> = line.split_whitespace().collect();
let cards: Vec<char> = split[0].chars().collect();
let bid: u32 = split[1].parse().unwrap();
Hand {
cards,
bid,
is_part_1: true,
}
})
.collect();
hands.sort();
println!("part 1: {}", get_total_winnings(&hands));
hands.iter_mut().for_each(|hand| hand.is_part_1 = false);
hands.sort();
println!("part 2: {}", get_total_winnings(&hands));
}
fn get_total_winnings(sorted_hands: &[Hand]) -> u32 {
sorted_hands
.iter()
.enumerate()
.map(|(i, hand)| hand.bid * (i as u32 + 1))
.sum()
}
#[derive(Debug, Eq, PartialEq, Clone)]
struct Hand {
cards: Vec<char>,
bid: u32,
is_part_1: bool,
}
fn get_occurrences(cards: &[char]) -> HashMap<char, u32> {
let mut occurrences: HashMap<char, u32> = HashMap::new();
for card in cards.iter() {
*occurrences.entry(*card).or_default() += 1;
}
occurrences
}
impl Hand {
fn type_score(&self) -> u8 {
let occurrences = get_occurrences(&self.cards);
match occurrences.values().max() {
Some(5) => 6,
Some(4) => 5,
Some(3) => {
if occurrences.values().any(|x| *x == 2) {
4
} else {
3
}
}
Some(2) => {
if occurrences.values().filter(|&x| *x == 2).count() == 2 {
2
} else {
1
}
}
Some(1) => 0,
_ => unreachable!(),
}
}
fn replace_joker(&self) -> Hand {
let mut without_jokers: Vec<char> =
self.cards.iter().filter(|&&c| c != 'J').copied().collect();
let occurrences = get_occurrences(&without_jokers);
without_jokers.sort_by(|a, b| occurrences[a].cmp(&occurrences[b]));
let most_common = without_jokers.last().unwrap_or(&'A');
let mut cards = without_jokers.clone();
for _i in 0..(5 - without_jokers.len()) {
cards.push(*most_common);
}
Hand { cards, ..*self }
}
}
impl Ord for Hand {
fn cmp(&self, other: &Self) -> Ordering {
let (self_score, other_score) = if self.is_part_1 {
(self.type_score(), other.type_score())
} else {
(
self.replace_joker().type_score(),
other.replace_joker().type_score(),
)
};
if self_score == other_score {
let order = if self.is_part_1 {
[
'A', 'K', 'Q', 'J', 'T', '9', '8', '7', '6', '5', '4', '3', '2',
]
} else {
[
'A', 'K', 'Q', 'T', '9', '8', '7', '6', '5', '4', '3', '2', 'J',
]
};
for (&self_card, &other_card) in self.cards.iter().zip(other.cards.iter()) {
let self_index = order.iter().position(|&x| x == self_card).unwrap();
let other_index = order.iter().position(|&x| x == other_card).unwrap();
match self_index.cmp(&other_index) {
Ordering::Equal => continue,
Ordering::Greater => return Ordering::Less,
Ordering::Less => return Ordering::Greater,
}
}
}
self_score.cmp(&other_score)
}
}
impl PartialOrd for Hand {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
Please register or sign in to comment