use std::{fmt::Display, io::stdin, str::FromStr}; use anyhow::{anyhow, Result, Error}; #[derive(Debug,Clone,Copy,Eq,PartialEq)] struct Card(char); #[derive(Debug,Clone,Copy,Eq,PartialEq)] struct Hand([Card; 5]); #[derive(Debug,Clone,Copy,Eq,PartialEq,Ord,PartialOrd)] enum Suit { HighCard, OnePair, TwoPairs, Three, Full, Four, Five, } impl Card { fn new(c: char) -> Result { match c { 'A'|'K'|'Q'|'J'|'T'|'2'..='9' => Ok(Self(c)), _ => Err(anyhow!("invalid card {c:?}")) } } fn value(self) -> usize { match self.0 { 'A' => 14, 'K' => 13, 'Q' => 12, 'J' => 11, 'T' => 10, '2'..='9' => char::to_digit(self.0, 10).unwrap() as usize, _ => panic!("invalid card"), } } } impl Ord for Card { fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.value().cmp(&other.value()) } } impl PartialOrd for Card { fn partial_cmp(&self, other: &Self) -> Option { Some(self.0.cmp(&other.0)) } } impl Display for Card { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.0.fmt(f) } } impl Hand { fn suit(&self) -> Suit { let mut cache = [0; 16]; let mut counts = [0; 5]; for v in self.0 { cache[v.value()] += 1; } for c in cache { if c > 0 { counts[c-1] += 1 } } match counts { [_,_,_,_,1] => Suit::Five, [_,_,_,1,_] => Suit::Four, [_,1,1,_,_] => Suit::Full, [_,_,1,_,_] => Suit::Three, [_,2,_,_,_] => Suit::TwoPairs, [_,1,_,_,_] => Suit::OnePair, _ => Suit::HighCard, } } } impl Ord for Hand { fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.suit().cmp(&other.suit()) .then_with(|| self.0.cmp(&other.0)) } } impl PartialOrd for Hand { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(&other)) } } impl FromStr for Hand { type Err = Error; fn from_str(s: &str) -> Result { if s.len() != 5 { return Err(anyhow!("Invalid hand {s}")) } let c = s.chars().map(Card::new) .collect::>>()?; Ok(Self([c[0], c[1], c[2], c[3], c[4]])) } } fn main() -> Result<()> { let mut data: Vec<(Hand, usize)> = stdin() .lines() .map(|l| -> Result<(Hand,usize)> { let l = l?; let (hand, bet) = l.split_once(' ') .ok_or_else(|| anyhow!("bad line {l:?}"))?; Ok((hand.parse()?, bet.parse()?)) }) .collect::>()?; data.sort_by(|a,b| a.0.cmp(&b.0)); let total: usize = data.iter() .enumerate() .map(|(rank, (_,bid))| bid*(rank+1) ) .sum(); println!("Part 1: total winnings {total}"); Ok(()) }