Optimized the solution and fix bugs that did not effect the results

This commit is contained in:
Dreaded_X 2023-12-07 13:57:59 +01:00
parent ac3bca6139
commit 47ff0fd30a
Signed by: Dreaded_X
GPG Key ID: 5A0CBFE3C3377FAA

View File

@ -1,7 +1,5 @@
#![feature(test)] #![feature(test)]
use std::cmp::max;
use anyhow::Result; use anyhow::Result;
use aoc::Solver; use aoc::Solver;
@ -49,7 +47,7 @@ mod tests {
} }
// Assign each card a value // Assign each card a value
fn card_value(card: &char, part2: bool) -> i32 { fn card_value(card: &char, part2: bool) -> u64 {
match card { match card {
'2' => 2, '2' => 2,
'3' => 3, '3' => 3,
@ -74,84 +72,87 @@ fn card_value(card: &char, part2: bool) -> i32 {
} }
} }
fn hand_value(cards: &[i32], part2: bool) -> usize { fn hand_value(cards: &[u64], part2: bool) -> u64 {
if part2 { // Partition the base into segments of four bits, where the first four represent the value of
(2..=14) // the right most card, the next four bits the second card from the right, etc
.map(|joker| { let base: u64 = cards
(2..=14)
.map(|index| {
// Count how many we have of that card, after replacing the joker
let count = cards
.iter() .iter()
.map(|card| if *card == 1 { joker } else { *card }) .rev()
.filter(|card| *card == index) .enumerate()
.count(); .map(|(index, card)| card << (index * 4))
.sum();
// Partition a number into segments of 3 bits // Count how many of each card we have
// First three bits is amount of high cards, seconds is the amount of pairs, etc let mut counts: Vec<_> = (1..=14)
// This should rank all cards based on type (ties still need to be resolved) .map(|index| cards.iter().filter(|card| **card == index).count())
1 << (count * 3) .collect();
})
.sum() if part2 {
}) // Find of which card we have the most
.max() let index_most = counts
.iter()
.enumerate()
.skip(1)
.max_by_key(|(_, count)| **count)
.unwrap() .unwrap()
.0;
// Add the jokes to that count
counts[index_most] += counts[0];
counts[0] = 0;
};
// Partition the rank into segments of 3 bits, lowest three bits is amount of single cards,
// next three bits is amount of pairs, etc
let rank: u64 = counts
.iter()
.map(|count| {
if *count > 0 {
1 << ((count - 1) * 3)
} else { } else {
// Loop over all possible cards 0
(2..=14)
.map(|index| {
// Count how many we have of that card
let count = cards.iter().filter(|card| **card == index).count();
// Partition a number into segments of 3 bits
// First three bits is amount of high cards, seconds is the amount of pairs, etc
// This should rank all cards based on type (ties still need to be resolved)
1 << (count * 3)
})
.sum()
} }
})
.sum();
// Shift over the rank and add the base two it
// Sorting by this number should rank all the cards according to the rules
(rank << (5 * 4)) + base
} }
fn solve(input: &str, part2: bool) -> usize { fn solve(input: &str, part2: bool) -> u64 {
// Parse each hand
let mut hands: Vec<_> = input let mut hands: Vec<_> = input
.lines() .lines()
.map(|line| { .map(|line| {
// Parse each line // Parse each line
let (cards, bid) = line.split_once(' ').unwrap(); let (cards, bid) = line.split_once(' ').unwrap();
let cards: Vec<_> = cards.chars().map(|card| card_value(&card, part2)).collect(); let cards: Vec<_> = cards.chars().map(|card| card_value(&card, part2)).collect();
let bid: usize = bid.parse().unwrap(); let bid: u64 = bid.parse().unwrap();
// Calculate the value of the hand // Calculate the value of the hand
let score = hand_value(&cards, part2); let value = hand_value(&cards, part2);
(score, cards, bid) (value, bid)
}) })
.collect(); .collect();
// Sort all the hands // Sort all the hands
hands.sort_by(|a, b| { hands.sort_by(|a, b| a.0.cmp(&b.0));
// Check if the score are equal
if a.0 == b.0 {
// If they are, sort by the card values
a.1.cmp(&b.1)
} else {
// Otherwise sort by score
a.0.cmp(&b.0)
}
});
// Calculate the total winnings // Calculate the total winnings
hands hands
.iter() .iter()
.enumerate() .enumerate()
.map(|(index, (_, _, bid))| bid * (index + 1)) .map(|(index, (_, bid))| bid * (index as u64 + 1))
.sum() .sum()
} }
// -- Solution -- // -- Solution --
pub struct Day; pub struct Day;
impl aoc::Solver for Day { impl aoc::Solver for Day {
type Output1 = usize; type Output1 = u64;
type Output2 = usize; type Output2 = u64;
fn day() -> u8 { fn day() -> u8 {
7 7