1use std::cmp::Reverse;
16use std::mem::replace;
17
18use crate::util::parse::*;
19
20pub struct Hand {
21 cards: [u8; 5],
22 bid: usize,
23}
24
25pub fn parse(input: &str) -> Vec<Hand> {
26 input
27 .lines()
28 .map(|line| {
29 let (prefix, suffix) = line.split_at(5);
30 let cards = prefix.as_bytes().try_into().unwrap();
31 let bid = suffix.unsigned();
32 Hand { cards, bid }
33 })
34 .collect()
35}
36
37pub fn part1(input: &[Hand]) -> usize {
38 winnings(input, 11)
39}
40
41pub fn part2(input: &[Hand]) -> usize {
42 winnings(input, 1)
43}
44
45fn winnings(input: &[Hand], jack: usize) -> usize {
46 let mut hands: Vec<_> = input
47 .iter()
48 .map(|&Hand { cards, bid }| {
49 let ranks = cards.map(|b| match b {
50 b'A' => 14,
51 b'K' => 13,
52 b'Q' => 12,
53 b'J' => jack,
54 b'T' => 10,
55 _ => b.to_decimal(),
56 });
57
58 let mut frequency = [0; 15];
59 for rank in ranks {
60 frequency[rank] += 1;
61 }
62
63 let jokers = replace(&mut frequency[1], 0);
65
66 let mut groups = ranks.map(|rank| replace(&mut frequency[rank], 0));
68 groups.sort_unstable_by_key(|&count| Reverse(count));
69 groups[0] += jokers;
70
71 let key = groups.iter().chain(&ranks).fold(0, |key, &value| (key << 4) | value);
73 (key, bid)
74 })
75 .collect();
76
77 hands.sort_unstable();
78 hands.into_iter().zip(1..).map(|((_, bid), rank)| bid * rank).sum()
79}