diff options
author | Gard Spreemann <gspr@nonempty.org> | 2023-12-12 11:26:30 +0100 |
---|---|---|
committer | Gard Spreemann <gspr@nonempty.org> | 2023-12-12 11:26:30 +0100 |
commit | c4f4348455b228318334208c8fd70e36bde0d135 (patch) | |
tree | 6225e7cdb7c15f3dd8747cbb7e47b170d5440a6c | |
parent | c98f19ae0044f8fe2dcca2037c0cbcadd7740531 (diff) |
-rw-r--r-- | 07/Cargo.toml | 6 | ||||
-rw-r--r-- | 07/src/part-2.rs | 35 | ||||
-rw-r--r-- | 07/src/stuff_joker.rs | 179 |
3 files changed, 217 insertions, 3 deletions
diff --git a/07/Cargo.toml b/07/Cargo.toml index 8455c36..b49811c 100644 --- a/07/Cargo.toml +++ b/07/Cargo.toml @@ -7,8 +7,8 @@ edition = "2021" name = "part-1" path = "src/part-1.rs" -#[[bin]] -#name = "part-2" -#path = "src/part-2.rs" +[[bin]] +name = "part-2" +path = "src/part-2.rs" [dependencies] diff --git a/07/src/part-2.rs b/07/src/part-2.rs new file mode 100644 index 0000000..e1f6ced --- /dev/null +++ b/07/src/part-2.rs @@ -0,0 +1,35 @@ +mod stuff; +mod stuff_joker; + +use crate::stuff::{ascii_to_u64, read_helper}; +use crate::stuff_joker::{Card, Hand}; + + +fn main() { + let mut stdin = std::io::stdin().lock(); + + let mut buf: Vec<u8> = Vec::new(); + let mut hands: Vec<(Hand, u64)> = Vec::new(); + + loop { + let num_bytes = read_helper(&mut stdin, &mut buf, b' ').expect("IO error"); + if num_bytes == 0 { break; } + let cards: [Card; 5] = std::array::from_fn(|i| Card::try_from(buf[i]).expect("Malformed input")); + let hand = Hand::new(cards); + + let num_bytes = read_helper(&mut stdin, &mut buf, b'\n').expect("IO error"); + if num_bytes == 0 { panic!("Malformed input"); } + let bid: u64 = ascii_to_u64(& buf); + + hands.push((hand, bid)); + } + + hands.sort_unstable_by(|(h1, _), (h2, _)| h1.cmp(h2)); + + let result: u64 = hands.into_iter() + .zip(1_u64..) + .map(|((_, bid), rank)| rank*bid) + .sum(); + + println!("{}", result); +} diff --git a/07/src/stuff_joker.rs b/07/src/stuff_joker.rs new file mode 100644 index 0000000..47f535f --- /dev/null +++ b/07/src/stuff_joker.rs @@ -0,0 +1,179 @@ +pub const NUM_CARDS: u8 = 13; + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum Card { + A, K, Q, J, T, + Nine, Eight, Seven, Six, Five, Four, Three, Two +} + +impl Card { + fn key(self: & Self) -> usize { + match self { + Self::Two => 0, + Self::Three => 1, + Self::Four => 2, + Self::Five => 3, + Self::Six => 4, + Self::Seven => 5, + Self::Eight => 6, + Self::Nine => 7, + Self::T => 8, + Self::J => 9, + Self::Q => 10, + Self::K => 11, + Self::A => 12 + } + } + + pub fn value(self: & Self) -> u8 { + match self { + Self::Two => 2, + Self::Three => 3, + Self::Four => 4, + Self::Five => 5, + Self::Six => 6, + Self::Seven => 7, + Self::Eight => 8, + Self::Nine => 9, + Self::T => 10, + Self::J => 1, + Self::Q => 11, + Self::K => 12, + Self::A => 13 + } + } +} + +impl TryFrom<u8> for Card { + type Error = &'static str; + + fn try_from(c: u8) -> Result<Self, Self::Error> { + match c { + b'A' => Ok(Self::A), + b'K' => Ok(Self::K), + b'Q' => Ok(Self::Q), + b'J' => Ok(Self::J), + b'T' => Ok(Self::T), + b'9' => Ok(Self::Nine), + b'8' => Ok(Self::Eight), + b'7' => Ok(Self::Seven), + b'6' => Ok(Self::Six), + b'5' => Ok(Self::Five), + b'4' => Ok(Self::Four), + b'3' => Ok(Self::Three), + b'2' => Ok(Self::Two), + _ => Err("ASCII character not a valid card") + } + } +} + +impl PartialOrd for Card { + fn partial_cmp(self: & Self, other: & Self) -> Option<core::cmp::Ordering> { + self.value().partial_cmp(& other.value()) + } +} + +impl Ord for Card { + fn cmp(self: & Self, other: & Self) -> core::cmp::Ordering { + self.value().cmp(& other.value()) + } +} + +#[derive(Debug, Eq, PartialEq)] +pub struct Hand { + cards: [Card; 5], + histogram: [u8; NUM_CARDS as usize], + num_jokers: u8 +} + +impl Hand { + fn count(self: & Self, card: Card) -> u8 { + if card == Card::J { + self.num_jokers + } + else { + self.histogram[card.key()] + } + } + + pub fn new(cards: [Card; 5]) -> Self { + let mut histogram: [u8; NUM_CARDS as usize] = [0; NUM_CARDS as usize]; + let mut num_jokers: u8 = 0; + for card in cards.into_iter() { + if card == Card::J { + num_jokers += 1; + } + else { + histogram[card.key()] += 1; + } + } + Self { cards: cards, histogram: histogram, num_jokers: num_jokers } + } + + pub fn is_n_of_a_kind(self: & Self, n: u8, count_jokers: bool) -> bool { + let num_jokers = if count_jokers { self.count(Card::J) } else { 0 }; + self.histogram.into_iter().find(|& count| count + num_jokers == n).is_some() + } + + pub fn is_full_house(self: & Self) -> bool { + (self.is_n_of_a_kind(3, false) && self.is_n_of_a_kind(2, false)) + || (self.is_two_pairs() && self.count(Card::J) >= 1 ) + } + + pub fn is_two_pairs(self: & Self) -> bool { + self.histogram.into_iter() + .position(|count| count == 2) + .and_then(|i| (& self.histogram[i+1..]).into_iter() + .position(|& count| count == 2)) + .is_some() + } + + pub fn strength(self: & Self) -> u8 { + if self.is_n_of_a_kind(5, true) { 6 } + else if self.is_n_of_a_kind(4, true) { 5 } + else if self.is_full_house() { 4 } + else if self.is_n_of_a_kind(3, true) { 3 } + else if self.is_two_pairs() { 2 } + else if self.is_n_of_a_kind(2, true) { 1 } + else { 0 } + } +} + +impl PartialOrd for Hand { + fn partial_cmp(self: & Self, other: & Self) -> Option<core::cmp::Ordering> { + let strength_ord = self.strength().cmp(& other.strength()); + if strength_ord == core::cmp::Ordering::Equal { + Some(self.cards.cmp(& other.cards)) + } + else { + Some(strength_ord) + } + } +} + +impl Ord for Hand { + fn cmp(self: & Self, other: & Self) -> core::cmp::Ordering { + let strength_ord = self.strength().cmp(& other.strength()); + if strength_ord == core::cmp::Ordering::Equal { + self.cards.cmp(& other.cards) + } + else { + strength_ord + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_joker_1() { + assert!(Hand::new([Card::T, Card::Five, Card::Five, Card::J, Card::Five]).is_n_of_a_kind(4, true)); + } + + #[test] + fn test_joker_fh() { + assert!(Hand::new([Card::T, Card::T, Card::Five, Card::Five, Card::J]).is_full_house()); + } +} |