summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGard Spreemann <gspr@nonempty.org>2023-12-12 11:26:30 +0100
committerGard Spreemann <gspr@nonempty.org>2023-12-12 11:26:30 +0100
commitc4f4348455b228318334208c8fd70e36bde0d135 (patch)
tree6225e7cdb7c15f3dd8747cbb7e47b170d5440a6c
parentc98f19ae0044f8fe2dcca2037c0cbcadd7740531 (diff)
Day 7, part 2 - done super uglyHEADmaster
-rw-r--r--07/Cargo.toml6
-rw-r--r--07/src/part-2.rs35
-rw-r--r--07/src/stuff_joker.rs179
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());
+ }
+}