use std::{cmp::Ordering, collections::HashMap}; use crate::common::load_input; // // Card // #[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Copy, Clone, Debug)] enum Card { A = 14, K = 13, Q = 12, J = 11, T = 10, N9 = 9, N8 = 8, N7 = 7, N6 = 6, N5 = 5, N4 = 4, N3 = 3, N2 = 2, } impl TryFrom for Card { type Error = &'static str; fn try_from(value: char) -> Result { match value { 'A' => Ok(Card::A), 'K' => Ok(Card::K), 'Q' => Ok(Card::Q), 'J' => Ok(Card::J), 'T' => Ok(Card::T), '9' => Ok(Card::N9), '8' => Ok(Card::N8), '7' => Ok(Card::N7), '6' => Ok(Card::N6), '5' => Ok(Card::N5), '4' => Ok(Card::N4), '3' => Ok(Card::N3), '2' => Ok(Card::N2), _ => Err("Not a card"), } } } // // Hand Value // #[derive(PartialEq, PartialOrd, Ord,Eq, Hash, Copy, Clone, Debug)] enum HandValue { FiveOfKind = 6, FourOfKind = 5, FullHouse = 4, ThreeOfKind = 3, TwoPair = 2, OnePair = 1, HighCard = 0, } // // Hand // #[derive(PartialEq, Eq, Copy, Clone, Debug)] struct Hand { cards: [Card; 5], } impl TryFrom<&str> for Hand { type Error = &'static str; fn try_from(value: &str) -> Result { let cards: Vec<_> = value.chars().map(|e| Card::try_from(e)).collect(); if !cards.iter().all(|e| e.is_ok()) { return Err("Invalid char"); } if cards.iter().count() != 5 { return Err("To many cards"); } let arr: [Card; 5] = [ cards.get(0).unwrap().unwrap(), cards.get(1).unwrap().unwrap(), cards.get(2).unwrap().unwrap(), cards.get(3).unwrap().unwrap(), cards.get(4).unwrap().unwrap(), ]; return Ok(Hand { cards: arr }); } } impl Hand { fn get_hand_value(&self) -> HandValue { let groups = self.get_card_cout(); // Check Five of a kind if groups.iter().any(|e| *e.1 == 5) { return HandValue::FiveOfKind; } // Check for Four of a kind if groups.iter().any(|e| *e.1 == 4) { return HandValue::FourOfKind; } //Check full house if groups.iter().any(|e| *e.1 == 3) && groups.iter().any(|e| *e.1 == 2) { return HandValue::FullHouse; } // Check for Three of a kind if groups.iter().any(|e| *e.1 == 3) { return HandValue::ThreeOfKind; } // Check for 1 and 2 Pairs let pairs = groups.iter().filter(|e| *e.1 == 2).count(); if pairs == 2 { return HandValue::TwoPair; } if pairs == 1 { return HandValue::OnePair; } return HandValue::HighCard; } fn get_card_cout(&self) -> HashMap { let mut rtn = HashMap::new(); self.cards.iter().for_each(|e| { match rtn.get(e) { None => rtn.insert(*e, 1u8), Some(v) => rtn.insert(*e, v + 1u8), }; }); return rtn; } } impl PartialOrd for Hand { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(&other)) } } impl Ord for Hand { fn cmp(&self, other: &Self) -> std::cmp::Ordering { let self_hand_value = self.get_hand_value(); let other_hand_value = other.get_hand_value(); if self_hand_value != other_hand_value { return self_hand_value.cmp(&other_hand_value); } // Compare the cards for (self_card, other_card) in self.cards.iter().zip(other.cards.iter()) { if self_card != other_card { return self_card.cmp(other_card); } } return Ordering::Equal; } } // // Everything else // fn parse_input(lines: &[String]) -> Vec<(Hand, u64)> { lines .iter() .map(|e| e.split_once(" ").unwrap()) .map(|e| (Hand::try_from(e.0).unwrap(), e.1.parse::().unwrap())) .collect() } pub fn run() -> Result> { let lines = load_input("./input/7.txt")?; let hands = parse_input(&lines); let mut orderd_hands = hands.clone(); orderd_hands.sort_by_key(|e| e.0); let score: u64 = orderd_hands.iter().enumerate().map(|e| (e.0 + 1) as u64 * (e.1.1)).sum(); Ok(score as i32) }