Begin 2023 day7 part2 by faffing about with generics
This commit is contained in:
parent
e1b0ca6d2e
commit
cb784f6d6b
@ -76,3 +76,35 @@ Now, you can determine the total winnings of this set of hands by adding up the
|
||||
with its rank (765 * 1 + 220 * 2 + 28 * 3 + 684 * 4 + 483 * 5). So the total winnings in this example are 6440.
|
||||
|
||||
Find the rank of every hand in your set. **What are the total winnings?**
|
||||
|
||||
## Part Two
|
||||
|
||||
To make things a little more interesting, the Elf introduces one additional rule. Now, `J` cards are jokers -
|
||||
wildcards that can act like whatever card would make the hand the strongest type possible.
|
||||
|
||||
To balance this, `J` **cards are now the weakest** individual cards, weaker even than `2`. The other cards stay in the
|
||||
same order: `A`, `K`, `Q`, `T`, `9`, `8`, `7`, `6`, `5`, `4`, `3`, `2`, `J`.
|
||||
|
||||
J cards can pretend to be whatever card is best for the purpose of determining hand type; for example, `QJJQ2`
|
||||
is now considered **four of a kind**. However, for the purpose of breaking ties between two hands of the same type,
|
||||
`J` is always treated as `J`, not the card it's pretending to be: `JKKK2` is weaker than `QQQQ2` because J is weaker
|
||||
than Q.
|
||||
|
||||
Now, the above example goes very differently:
|
||||
|
||||
```
|
||||
32T3K 765
|
||||
T55J5 684
|
||||
KK677 28
|
||||
KTJJT 220
|
||||
QQQJA 483
|
||||
```
|
||||
|
||||
- `32T3K` is still the only one pair; it doesn't contain any jokers, so its strength doesn't increase.
|
||||
- `KK677` is now the only two pair, making it the second-weakest hand.
|
||||
- `T55J5`, `KTJJT`, and `QQQJA` are now all four of a kind! `T55J5` gets rank 3, `QQQJA` gets rank 4, and `KTJJT` gets rank 5.
|
||||
|
||||
With the new joker rule, the total winnings in this example are `5905`.
|
||||
|
||||
Using the new joker rule, find the rank of every hand in your set. **What are the new total winnings?**
|
||||
|
||||
|
@ -1,14 +1,14 @@
|
||||
use crate::HandType::{
|
||||
FiveOfAKind, FourOfAKind, FullHouse, HighCard, OnePair, ThreeOfAKind, TwoPair,
|
||||
};
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
use HandType::*;
|
||||
|
||||
const FILE_STR: &str = include_str!("input.txt");
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialOrd, Ord, PartialEq, Eq, Hash)]
|
||||
#[derive(Copy, Clone, Debug, Default, PartialOrd, Ord, PartialEq, Eq, Hash)]
|
||||
#[repr(u8)]
|
||||
enum CardType {
|
||||
enum NormalCardType {
|
||||
#[default]
|
||||
Two = 0,
|
||||
Three,
|
||||
@ -25,9 +25,9 @@ enum CardType {
|
||||
Ace,
|
||||
}
|
||||
|
||||
impl From<char> for CardType {
|
||||
impl From<char> for NormalCardType {
|
||||
fn from(value: char) -> Self {
|
||||
use CardType::*;
|
||||
use NormalCardType::*;
|
||||
|
||||
match value {
|
||||
'2' => Two,
|
||||
@ -48,39 +48,90 @@ impl From<char> for CardType {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, PartialOrd, Ord, PartialEq, Eq, Hash)]
|
||||
#[repr(u8)]
|
||||
enum WildJokerCardType {
|
||||
#[default]
|
||||
Joker = 0,
|
||||
Two,
|
||||
Three,
|
||||
Four,
|
||||
Five,
|
||||
Six,
|
||||
Seven,
|
||||
Eight,
|
||||
Nine,
|
||||
Jack,
|
||||
Queen,
|
||||
King,
|
||||
Ace,
|
||||
}
|
||||
|
||||
impl From<char> for WildJokerCardType {
|
||||
fn from(value: char) -> Self {
|
||||
use WildJokerCardType::*;
|
||||
match value {
|
||||
'J' => Joker,
|
||||
'2' => Two,
|
||||
'3' => Three,
|
||||
'4' => Four,
|
||||
'5' => Five,
|
||||
'6' => Six,
|
||||
'7' => Seven,
|
||||
'8' => Eight,
|
||||
'9' => Nine,
|
||||
'T' => Jack,
|
||||
'Q' => Queen,
|
||||
'K' => King,
|
||||
'A' => Ace,
|
||||
_ => panic!("Invalid card character"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type PartOne = NormalCardType;
|
||||
type PartTwo = WildJokerCardType;
|
||||
|
||||
trait CardType: Eq + Copy + PartialOrd + Ord + Debug + Hash + From<char> {}
|
||||
impl CardType for NormalCardType {}
|
||||
impl CardType for WildJokerCardType {}
|
||||
|
||||
#[derive(Debug, Default, PartialEq, Eq)]
|
||||
struct Hand {
|
||||
cards: [CardType; 5],
|
||||
struct Hand<T> {
|
||||
cards: [T; 5],
|
||||
kind: HandType,
|
||||
bet: usize,
|
||||
}
|
||||
|
||||
impl Hand {
|
||||
impl<T: CardType> Hand<T>
|
||||
where
|
||||
HandType: From<[T; 5]>,
|
||||
{
|
||||
fn parse(line: &str) -> Self {
|
||||
let mut parts = line.split_whitespace();
|
||||
let raw_hand = parts.next().unwrap();
|
||||
let raw_bet = parts.next().unwrap();
|
||||
let cards: [CardType; 5] = raw_hand
|
||||
let cards: [T; 5] = raw_hand
|
||||
.trim()
|
||||
.chars()
|
||||
.map(CardType::from)
|
||||
.collect::<Vec<CardType>>()
|
||||
.map(|ch| ch.into())
|
||||
.collect::<Vec<T>>()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
let bet = raw_bet.trim().parse::<usize>().unwrap();
|
||||
let kind = HandType::from(cards.clone());
|
||||
let kind = HandType::from(cards);
|
||||
|
||||
Hand { cards, kind, bet }
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Hand {
|
||||
impl<T: CardType> PartialOrd for Hand<T> {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Hand {
|
||||
impl<T: CardType> Ord for Hand<T> {
|
||||
/// Implement the sorting for each hand, first comparing the type of
|
||||
/// hand, and then comparing the individual cards, if necessary
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
@ -88,8 +139,8 @@ impl Ord for Hand {
|
||||
return self.kind.cmp(&other.kind);
|
||||
}
|
||||
|
||||
for (i, card) in self.cards.iter().enumerate() {
|
||||
if card != &other.cards[i] {
|
||||
for (i, card) in self.cards.into_iter().enumerate() {
|
||||
if card != other.cards[i] {
|
||||
return card.cmp(&other.cards[i]);
|
||||
}
|
||||
}
|
||||
@ -98,7 +149,7 @@ impl Ord for Hand {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, PartialOrd, Ord, PartialEq, Eq, Copy, Clone)]
|
||||
#[derive(Debug, Default, PartialOrd, Ord, PartialEq, Eq, Copy, Clone, Hash)]
|
||||
#[repr(u8)]
|
||||
enum HandType {
|
||||
#[default]
|
||||
@ -111,12 +162,18 @@ enum HandType {
|
||||
FiveOfAKind,
|
||||
}
|
||||
|
||||
impl From<[CardType; 5]> for HandType {
|
||||
fn from(value: [CardType; 5]) -> Self {
|
||||
impl HandType {
|
||||
fn from_cards(value: [WildJokerCardType; 5]) -> Self {
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: CardType> From<[T; 5]> for HandType {
|
||||
fn from(value: [T; 5]) -> Self {
|
||||
let mut cards = Vec::from(value);
|
||||
cards.sort_unstable();
|
||||
|
||||
let mut count_map: HashMap<CardType, usize> = HashMap::new();
|
||||
let mut count_map: HashMap<T, usize> = HashMap::new();
|
||||
cards.into_iter().for_each(|ct| {
|
||||
match count_map.get(&ct) {
|
||||
Some(count) => count_map.insert(ct, *count + 1),
|
||||
@ -139,17 +196,17 @@ impl From<[CardType; 5]> for HandType {
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct Game {
|
||||
hands: Vec<Hand>,
|
||||
struct Game<T> {
|
||||
hands: Vec<Hand<T>>,
|
||||
}
|
||||
|
||||
impl Game {
|
||||
fn parse(input: &str) -> Self {
|
||||
impl<T: CardType> Game<T> {
|
||||
fn parse(input: &str) -> Game<T> {
|
||||
let hands = input
|
||||
.split('\n')
|
||||
.filter(|s| !s.is_empty())
|
||||
.map(Hand::parse)
|
||||
.collect::<Vec<Hand>>();
|
||||
.collect::<Vec<Hand<T>>>();
|
||||
|
||||
Game { hands }
|
||||
}
|
||||
@ -168,14 +225,19 @@ impl Game {
|
||||
}
|
||||
|
||||
fn part_one() {
|
||||
let mut game = Game::parse(FILE_STR);
|
||||
let mut game: Game<PartOne> = Game::parse(FILE_STR);
|
||||
let score = game.get_score_sum();
|
||||
|
||||
println!("Part 1: Sum of scores: {}", score);
|
||||
}
|
||||
|
||||
fn part_two() {
|
||||
let _game: Game<PartTwo> = Game::parse(FILE_STR);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
part_one();
|
||||
part_two();
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@ -185,7 +247,10 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn get_score_sum() {
|
||||
let mut game = Game::parse(EXAMPLE_FILE_STR);
|
||||
let mut game: Game<PartOne> = Game::parse(EXAMPLE_FILE_STR);
|
||||
assert_eq!(6440, game.get_score_sum());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_wild_score_sum() {}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user