use std::{fs::read_to_string, collections::{HashMap, btree_map::Values}}; #[derive(Debug, Copy, Clone)] #[derive(PartialEq, PartialOrd, Eq, Ord)] enum Rank { HighCard, OnePair, TwoPair, ThreeOfAKind, FullHouse, FourOfAKind, FiveOfAKind, } impl Rank { fn signature(&self) -> Vec { match self { Rank::HighCard => vec![1, 1, 1, 1, 1], Rank::OnePair => vec![2, 1, 1, 1], Rank::TwoPair => vec![2, 2, 1], Rank::ThreeOfAKind => vec![3, 1, 1], Rank::FullHouse => vec![3, 2], Rank::FourOfAKind => vec![4, 1], Rank::FiveOfAKind => vec![5] } } fn matches(&self, hand: &Vec) -> bool { let signature = self.signature(); if hand.len() != signature.len() { return false; } signature.iter().zip(hand.iter()).filter(|&(lhs, rhs)| lhs == rhs).count() == signature.len() } fn mapping() -> HashMap, Rank> { HashMap::from([ (Rank::HighCard{}.signature(), Rank::HighCard), (Rank::OnePair{}.signature(), Rank::OnePair), (Rank::TwoPair{}.signature(), Rank::TwoPair), (Rank::ThreeOfAKind{}.signature(), Rank::ThreeOfAKind), (Rank::FullHouse{}.signature(), Rank::FullHouse), (Rank::FourOfAKind{}.signature(), Rank::FourOfAKind), (Rank::FiveOfAKind{}.signature(), Rank::FiveOfAKind), ]) } fn card_values() -> HashMap { HashMap::from([ (b'2', 0), (b'3', 1), (b'4', 2), (b'5', 3), (b'6', 4), (b'7', 5), (b'8', 6), (b'9', 7), (b'T', 8), (b'J', 9), (b'Q', 10), (b'K', 11), (b'A', 12), ]) } fn parse(line: &str, mapping: &HashMap, Rank>, values: &HashMap) -> (Rank, u64) { let mut counts = HashMap::::new(); let mut tiebreaker: u64 = 0; for idx in 0..line.len() { *counts.entry(line.as_bytes()[idx]).or_insert(0) += 1; tiebreaker = tiebreaker * 100 + values[&line.as_bytes()[idx]] as u64; } let mut signature = counts.values().map(|a| *a).collect::>(); signature.sort_by(|a, b| b.cmp(a)); (mapping[&signature], tiebreaker) } } struct Hand { cards: String, score: u64, rank: Rank, tiebreaker: u64, } impl Hand { fn parse(line: &str, mapping: &HashMap, Rank>, values: &HashMap) -> Hand { let (cards, score) = line.split_once(' ').unwrap(); let (rank, tiebreaker) = Rank::parse(cards, mapping, values); Hand{cards: String::from(cards), score: score.parse::().unwrap(), rank, tiebreaker} } } fn main() { let mapping = Rank::mapping(); let card_values = Rank::card_values(); let mut hands = read_to_string("input.txt").unwrap().lines().map(|line| { Hand::parse(line, &mapping, &card_values) }).collect::>(); hands.sort_by(|lhs, rhs| { if lhs.rank == rhs.rank { return lhs.tiebreaker.cmp(&rhs.tiebreaker); } lhs.rank.cmp(&rhs.rank) }); let mut score_base = 1; let mut points = 0; for hand in &hands { points += score_base * hand.score; score_base += 1; } println!("Total points: {}", points); }