07.rs
1 #![feature(test)] 2 3 use counter::Counter; 4 use itertools::Itertools; 5 6 type Input = Vec<Hand>; 7 8 #[derive(Debug)] 9 struct Hand { 10 cards: [Card; 5], 11 bid: u64, 12 } 13 14 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 15 struct Card(u8); 16 17 impl Card { 18 fn from_byte(b: u8) -> Self { 19 Self(match b { 20 b'2'..=b'9' => b - b'0', 21 b'T' => 10, 22 b'J' => 11, 23 b'Q' => 12, 24 b'K' => 13, 25 b'A' => 14, 26 _ => panic!(), 27 }) 28 } 29 30 fn is_joker(&self) -> bool { 31 self.0 == 11 32 } 33 34 fn remap_joker(self) -> Self { 35 if self.is_joker() { 36 Self(0) 37 } else { 38 self 39 } 40 } 41 } 42 43 impl Hand { 44 fn sort_key<const JOKERS: bool>(&self) -> impl Ord + std::fmt::Debug { 45 let cnt = self 46 .cards 47 .into_iter() 48 .filter(|card| !JOKERS || !card.is_joker()) 49 .collect::<Counter<_>>() 50 .into_map() 51 .into_values() 52 .sorted_unstable() 53 .collect_vec(); 54 55 let ty = match &cnt[..] { 56 [] | [_] => 6, 57 [1, _] => 5, 58 [2, _] => 4, 59 [1, 1, _] => 3, 60 [1, 2, _] => 2, 61 [1, 1, 1, _] => 1, 62 _ => 0, 63 }; 64 65 let cards = if JOKERS { 66 self.cards.map(Card::remap_joker) 67 } else { 68 self.cards 69 }; 70 71 (ty, cards) 72 } 73 } 74 75 fn setup(input: &str) -> Input { 76 input 77 .lines() 78 .map(|line| { 79 let mut line = line.split_whitespace(); 80 let cards = line 81 .next() 82 .unwrap() 83 .bytes() 84 .map(Card::from_byte) 85 .collect_vec() 86 .try_into() 87 .unwrap(); 88 let bid = line.next().unwrap().parse().unwrap(); 89 Hand { cards, bid } 90 }) 91 .collect() 92 } 93 94 fn solve<O: Ord>(input: &Input, sort_key: fn(&Hand) -> O) -> u64 { 95 input 96 .iter() 97 .sorted_by_cached_key(|&hand| sort_key(hand)) 98 .enumerate() 99 .map(|(i, hand)| (i as u64 + 1) * hand.bid) 100 .sum() 101 } 102 103 fn part1(input: &Input) -> u64 { 104 solve(input, Hand::sort_key::<false>) 105 } 106 107 fn part2(input: &Input) -> u64 { 108 solve(input, Hand::sort_key::<true>) 109 } 110 111 aoc::main!(2023, 7, ex: 1);