add initial cribbage scoring
authorGeoffrey Allott <geoffrey@allott.email>
Sat, 26 Jun 2021 20:21:19 +0000 (21:21 +0100)
committerGeoffrey Allott <geoffrey@allott.email>
Sat, 26 Jun 2021 20:21:19 +0000 (21:21 +0100)
src/card.rs
src/game/cribbage/mod.rs [new file with mode: 0644]
src/game/cribbage/score.rs [new file with mode: 0644]
src/game/mod.rs

index 8ffb0f06ce30f6f46ceca3e4fc76813ae6dd0abf..9a26e8c656f080c29ce310885ec0a7935e6289ad 100644 (file)
@@ -20,6 +20,26 @@ pub enum Rank {
     Ace = 14,
 }
 
+impl Rank {
+    pub fn ace_low_rank(self) -> u32 {
+        match self {
+            Ace => 1,
+            Two => 2,
+            Three => 3,
+            Four => 4,
+            Five => 5,
+            Six => 6,
+            Seven => 7,
+            Eight => 8,
+            Nine => 9,
+            Ten => 10,
+            Jack => 11,
+            Queen => 12,
+            King => 13,
+        }
+    }
+}
+
 impl Display for Rank {
     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
         f.write_str(match *self {
diff --git a/src/game/cribbage/mod.rs b/src/game/cribbage/mod.rs
new file mode 100644 (file)
index 0000000..0d47f79
--- /dev/null
@@ -0,0 +1 @@
+mod score;
diff --git a/src/game/cribbage/score.rs b/src/game/cribbage/score.rs
new file mode 100644 (file)
index 0000000..24c5da9
--- /dev/null
@@ -0,0 +1,372 @@
+use std::fmt::{self, Display};
+
+use itertools::Itertools;
+
+use crate::card::{Card, Rank};
+use crate::card::Rank::*;
+
+#[derive(Copy, Clone, Debug)]
+pub struct Score {
+    nob: u8,
+    flush: u8,
+    fifteen: u8,
+    pair: u8,
+    run: u8,
+}
+
+impl Score {
+    pub fn points(&self) -> u8 {
+        self.nob + self.flush + self.fifteen + self.pair + self.run
+    }
+}
+
+impl Display for Score {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match self {
+            Score { nob: 0, flush: 0, fifteen: 0, pair: 0, run: 0 } => f.write_str("Nineteen"),
+            Score { nob: 0, flush: 0, fifteen: 2, pair: 0, run: 0 } => f.write_str("Fifteen two, and the rest won't do"),
+            Score { nob: 0, flush: 0, fifteen: 4, pair: 0, run: 0 } => f.write_str("Fifteen two, fifteen four, look all day, see no more"),
+            Score { nob: 0, flush: 0, fifteen: 6, pair: 0, run: 0 } => f.write_str("Fifteen two, fifteen four, fifteen six, pick up sticks"),
+            Score { nob, flush, fifteen, pair, run } => {
+                let fifteen = match fifteen {
+                    0 => "",
+                    2 => "Fifteen two",
+                    4 => "Fifteen two, fifteen four",
+                    6 => "Fifteen two, fifteen four, fifteen six",
+                    8 => "Fifteen two, fifteen four, fifteen six, fifteen eight",
+                    10 => "Fifteen two, fifteen four, fifteen six, fifteen eight, fifteen ten",
+                    12 => "Fifteen two, fifteen four, fifteen six, fifteen eight, fifteen ten, fifteen twelve",
+                    14 => "Fifteen two, fifteen four, fifteen six, fifteen eight, fifteen ten, fifteen twelve, fifteen fourteen",
+                    16 => "Fifteen two, fifteen four, fifteen six, fifteen eight, fifteen ten, fifteen twelve, fifteen fourteen, fifteen sixteen",
+                    _ => return write!(f, "[ERROR] {:?}", self),
+                };
+                let pair_and_run = match (fifteen, pair, run) {
+                    (_, 0, 0) => "",
+                    ("", 2, 0) => "Two",
+                    (_, 2, 0) => " and two",
+                    ("", 0, 3) => "Three",
+                    (_, 0, 3) => " and three",
+                    ("", 4, 0) => "Two and two",
+                    (_, 4, 0) => " and two and two",
+                    ("", 0, 4) => "Four",
+                    (_, 0, 4) => " and four",
+                    ("", 2, 3) => "Two and three",
+                    (_, 2, 3) => " and two and three",
+                    ("", 0, 5) => "Five",
+                    (_, 0, 5) => " and five",
+                    ("", 6, 0) => "Six",
+                    (_, 6, 0) => " and six",
+                    ("", 8, 0) => "Six and two",
+                    (_, 8, 0) => " and six and two",
+                    ("", 2, 6) => "Eight",
+                    (_, 2, 6) => " and eight",
+                    ("", 2, 8) => "Ten",
+                    (_, 2, 8) => " and ten",
+                    ("", 12, 0) => "Twelve",
+                    (_, 12, 0) => " and twelve",
+                    ("", 6, 9) => "Fifteen",
+                    (_, 6, 9) => " and fifteen",
+                    ("", 4, 12) => "Sixteen",
+                    (_, 4, 12) => " and sixteen",
+                    _ => return write!(f, "[ERROR] {:?}", self),
+                };
+                let flush = match (fifteen, pair_and_run, flush) {
+                    (_, _, 0) => "",
+                    ("", "", 4) => "Four",
+                    (_, _, 4) => " and four",
+                    ("", "", 5) => "Five",
+                    (_, _, 5) => " and five",
+                    _ => return write!(f, "[ERROR] {:?}", self),
+                };
+                let nob = match (fifteen, pair_and_run, flush, nob) {
+                    (_, _, _, 0) => "",
+                    ("", "", "", 1) => "One for his nob",
+                    (_, _, _, 1) => " and one for his nob",
+                    _ => return write!(f, "[ERROR] {:?}", self),
+                };
+                match (fifteen, pair_and_run, flush, nob) {
+                    (fifteen, "", "", "") => f.write_str(fifteen),
+                    ("", pair_and_run, "", "") => f.write_str(pair_and_run),
+                    ("", "", flush, "") => f.write_str(flush),
+                    ("", "", "", nob) => f.write_str(nob),
+                    (fifteen, pair_and_run, flush, nob) => {
+                        f.write_str(fifteen)?;
+                        f.write_str(pair_and_run)?;
+                        f.write_str(flush)?;
+                        f.write_str(nob)?;
+                        write!(f, " is {}", self.points())
+                    }
+                }
+            }
+        }
+    }
+}
+
+#[derive(Copy, Clone, Debug)]
+pub struct PeggingScore {
+    fifteen: u8,
+    thirty_one: u8,
+    pair: u8,
+    run: u8,
+}
+
+impl PeggingScore {
+    pub fn points(&self) -> u8 {
+        self.fifteen + self.thirty_one + self.pair + self.run
+    }
+}
+
+impl Display for PeggingScore {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match self {
+            PeggingScore { fifteen: 0, thirty_one: 0, pair: 0, run: 0 } => Ok(()),
+            PeggingScore { fifteen: 2, thirty_one: 0, pair: 0, run: 0 } => f.write_str("Fifteen for two"),
+            PeggingScore { fifteen: 2, thirty_one: 0, pair: 2, run: 0 } => f.write_str("Fifteen two and two is four"),
+            PeggingScore { fifteen: 2, thirty_one: 0, pair: 0, run: 3 } => f.write_str("Fifteen two and three is five"),
+            PeggingScore { fifteen: 2, thirty_one: 0, pair: 0, run: 4 } => f.write_str("Fifteen two and four is six"),
+            PeggingScore { fifteen: 2, thirty_one: 0, pair: 0, run: 5 } => f.write_str("Fifteen two and five is seven"),
+            PeggingScore { fifteen: 2, thirty_one: 0, pair: 6, run: 0 } => f.write_str("Fifteen two and six is eight"),
+            PeggingScore { fifteen: 2, thirty_one: 0, pair: 12, run: 0 } => f.write_str("Fifteen two and twelve is fourteen"),
+            PeggingScore { fifteen: 0, thirty_one: 2, pair: 0, run: 0 } => f.write_str("Thirty-one for two"),
+            PeggingScore { fifteen: 0, thirty_one: 2, pair: 2, run: 0 } => f.write_str("Thirty-one for two and two is four"),
+            PeggingScore { fifteen: 0, thirty_one: 2, pair: 0, run: 3 } => f.write_str("Thirty-one for two and three is five"),
+            PeggingScore { fifteen: 0, thirty_one: 2, pair: 0, run: 4 } => f.write_str("Thirty-one for two and four is six"),
+            PeggingScore { fifteen: 0, thirty_one: 2, pair: 0, run: 5 } => f.write_str("Thirty-one for two and five is seven"),
+            PeggingScore { fifteen: 0, thirty_one: 2, pair: 0, run: 6 } => f.write_str("Thirty-one for two and six is eight"),
+            PeggingScore { fifteen: 0, thirty_one: 2, pair: 6, run: 0 } => f.write_str("Thirty-one for two and six is eight"),
+            PeggingScore { fifteen: 0, thirty_one: 2, pair: 0, run: 7 } => f.write_str("Thirty-one for two and seven is nine"),
+            PeggingScore { fifteen: 0, thirty_one: 2, pair: 12, run: 0 } => f.write_str("Thirty-one for two and twelve is fourteen"),
+            PeggingScore { fifteen: 0, thirty_one: 0, pair: 2, run: 0 } => f.write_str("Two"),
+            PeggingScore { fifteen: 0, thirty_one: 0, pair: 0, run: 3 } => f.write_str("Three"),
+            PeggingScore { fifteen: 0, thirty_one: 0, pair: 0, run: 4 } => f.write_str("Four"),
+            PeggingScore { fifteen: 0, thirty_one: 0, pair: 0, run: 5 } => f.write_str("Five"),
+            PeggingScore { fifteen: 0, thirty_one: 0, pair: 0, run: 6 } => f.write_str("Six"),
+            PeggingScore { fifteen: 0, thirty_one: 0, pair: 6, run: 0 } => f.write_str("Six"),
+            PeggingScore { fifteen: 0, thirty_one: 0, pair: 0, run: 7 } => f.write_str("Seven"),
+            PeggingScore { fifteen: 0, thirty_one: 0, pair: 12, run: 0 } => f.write_str("Twelve"),
+            _ => write!(f, "[ERROR] {:?}", self),
+        }
+    }
+}
+
+fn value(rank: Rank) -> u32 {
+    match rank {
+        Ace => 1,
+        Two => 2,
+        Three => 3,
+        Four => 4,
+        Five => 5,
+        Six => 6,
+        Seven => 7,
+        Eight => 8,
+        Nine => 9,
+        Ten => 10,
+        Jack => 10,
+        Queen => 10,
+        King => 10,
+    }
+}
+
+fn sum_value(cards: &[Card]) -> u32 {
+    cards.iter().map(|card| card.rank).map(value).sum()
+}
+
+fn is_run(cards: &[Card]) -> bool {
+    cards.iter().map(|card| card.rank.ace_low_rank()).sorted().tuple_windows().all(|(rank1, rank2)| rank2 == rank1 + 1)
+}
+
+pub fn score_pegging(cards: &[Card]) -> PeggingScore {
+    let mut score = PeggingScore {
+        fifteen: 0,
+        thirty_one: 0,
+        pair: 0,
+        run: 0,
+    };
+    
+    if sum_value(cards) == 15 {
+        score.fifteen += 2;
+    }
+
+    if sum_value(cards) == 31 {
+        score.thirty_one += 2;
+    }
+
+    for start in 0..cards.len() {
+        let run = &cards[start..];
+        if run.len() < 3 {
+            break;
+        }
+        if is_run(run) {
+            score.run += run.len() as u8;
+            break;
+        }
+    }
+
+    for start in 0..cards.len() {
+        let cards = &cards[start..];
+        if cards.len() < 2 {
+            break;
+        }
+        if cards.iter().all_equal() {
+            score.pair += (cards.len() * (cards.len() - 1)) as u8;
+            break;
+        }
+    }
+
+    score
+}
+
+pub fn score_4_card_cribbage_hand(cards: [Card; 4], turnup: Card, is_box: bool) -> Score {
+    let mut score = Score {
+        nob: 0,
+        flush: 0,
+        fifteen: 0,
+        pair: 0,
+        run: 0,
+    };
+
+    for card in &cards {
+        if card.rank == Jack && card.suit == turnup.suit {
+            score.nob += 1;
+        }
+    }
+
+    if cards[0].suit == cards[1].suit && cards[1].suit == cards[2].suit && cards[2].suit == cards[3].suit && cards[3].suit == turnup.suit {
+        score.flush += 5;
+    } else if !is_box && cards[0].suit == cards[1].suit && cards[1].suit == cards[2].suit && cards[2].suit == cards[3].suit {
+        score.flush += 4;
+    }
+
+    let cards = [cards[0], cards[1], cards[2], cards[3], turnup];
+    for cards in cards.iter().cloned().powerset() {
+        if sum_value(&cards) == 15 {
+            score.fifteen += 2;
+        }
+    }
+
+    for cards in cards.iter().cloned().combinations(2) {
+        if cards[0].rank == cards[1].rank {
+            score.pair += 2;
+        }
+    }
+
+    for &run_length in &[5, 4, 3] {
+        let runs = cards.iter().cloned().combinations(run_length)
+            .filter(|cards| is_run(cards))
+            .count();
+        if runs > 0 {
+            score.run += (run_length * runs) as u8;
+            break;
+        }
+    }
+
+    score
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    use crate::card::*;
+
+    #[test]
+    fn cribbage_hand_rankings_with_display() {
+        let score = score_4_card_cribbage_hand([ACE_OF_HEARTS, ACE_OF_SPADES, TWO_OF_CLUBS, TWO_OF_DIAMONDS], THREE_OF_HEARTS, false);
+        assert_eq!(16, score.points());
+        assert_eq!("Sixteen", format!("{}", score));
+
+        let score = score_4_card_cribbage_hand([ACE_OF_HEARTS, ACE_OF_SPADES, SIX_OF_SPADES, SEVEN_OF_CLUBS], SEVEN_OF_DIAMONDS, false);
+        assert_eq!(12, score.points());
+        assert_eq!("Fifteen two, fifteen four, fifteen six, fifteen eight and two and two is 12", format!("{}", score));
+
+        let score = score_4_card_cribbage_hand([ACE_OF_HEARTS, SEVEN_OF_SPADES, SEVEN_OF_CLUBS, SEVEN_OF_HEARTS], SEVEN_OF_DIAMONDS, false);
+        assert_eq!(24, score.points());
+        assert_eq!("Fifteen two, fifteen four, fifteen six, fifteen eight, fifteen ten, fifteen twelve and twelve is 24", format!("{}", score));
+
+        let score = score_4_card_cribbage_hand([FIVE_OF_CLUBS, FIVE_OF_DIAMONDS, FIVE_OF_HEARTS, JACK_OF_SPADES], TEN_OF_SPADES, false);
+        assert_eq!(21, score.points());
+        assert_eq!("Fifteen two, fifteen four, fifteen six, fifteen eight, fifteen ten, fifteen twelve, fifteen fourteen and six and one for his nob is 21", format!("{}", score));
+
+        let score = score_4_card_cribbage_hand([SIX_OF_CLUBS, SEVEN_OF_DIAMONDS, EIGHT_OF_HEARTS, NINE_OF_SPADES], NINE_OF_CLUBS, false);
+        assert_eq!(16, score.points());
+        assert_eq!("Fifteen two, fifteen four, fifteen six and ten is 16", format!("{}", score));
+
+        let score = score_4_card_cribbage_hand([NINE_OF_CLUBS, TEN_OF_DIAMONDS, JACK_OF_HEARTS, QUEEN_OF_SPADES], KING_OF_CLUBS, false);
+        assert_eq!(5, score.points());
+        assert_eq!("Five", format!("{}", score));
+    }
+
+    #[test]
+    fn cribbage_hand_rankings() {
+        assert_eq!(16, score_4_card_cribbage_hand([ACE_OF_CLUBS, ACE_OF_DIAMONDS, TWO_OF_HEARTS, TWO_OF_SPADES], THREE_OF_CLUBS, false).points());
+        assert_eq!(12, score_4_card_cribbage_hand([ACE_OF_CLUBS, ACE_OF_DIAMONDS, SIX_OF_HEARTS, SEVEN_OF_SPADES], SEVEN_OF_CLUBS, false).points());
+        assert_eq!(13, score_4_card_cribbage_hand([ACE_OF_CLUBS, ACE_OF_DIAMONDS, SIX_OF_HEARTS, SEVEN_OF_SPADES], EIGHT_OF_CLUBS, false).points());
+        assert_eq!(12, score_4_card_cribbage_hand([ACE_OF_CLUBS, ACE_OF_DIAMONDS, SEVEN_OF_HEARTS, SEVEN_OF_SPADES], EIGHT_OF_CLUBS, false).points());
+        assert_eq!(15, score_4_card_cribbage_hand([ACE_OF_CLUBS, TWO_OF_DIAMONDS, THREE_OF_HEARTS, THREE_OF_SPADES], THREE_OF_CLUBS, false).points());
+        assert_eq!(12, score_4_card_cribbage_hand([ACE_OF_CLUBS, FOUR_OF_DIAMONDS, FOUR_OF_HEARTS, FOUR_OF_SPADES], TEN_OF_CLUBS, false).points());
+        assert_eq!(13, score_4_card_cribbage_hand([ACE_OF_CLUBS, FOUR_OF_DIAMONDS, FOUR_OF_HEARTS, JACK_OF_SPADES], FOUR_OF_SPADES, false).points());
+        assert_eq!(24, score_4_card_cribbage_hand([ACE_OF_CLUBS, SEVEN_OF_DIAMONDS, SEVEN_OF_HEARTS, SEVEN_OF_SPADES], SEVEN_OF_CLUBS, false).points());
+        assert_eq!(20, score_4_card_cribbage_hand([TWO_OF_CLUBS, TWO_OF_DIAMONDS, TWO_OF_HEARTS, TWO_OF_SPADES], NINE_OF_CLUBS, false).points());
+        assert_eq!(17, score_4_card_cribbage_hand([TWO_OF_CLUBS, THREE_OF_DIAMONDS, FOUR_OF_HEARTS, FOUR_OF_SPADES], FOUR_OF_CLUBS, false).points());
+        assert_eq!(16, score_4_card_cribbage_hand([TWO_OF_CLUBS, TWO_OF_DIAMONDS, THREE_OF_HEARTS, THREE_OF_SPADES], FOUR_OF_CLUBS, false).points());
+        assert_eq!(17, score_4_card_cribbage_hand([TWO_OF_CLUBS, THREE_OF_DIAMONDS, THREE_OF_HEARTS, THREE_OF_SPADES], FOUR_OF_CLUBS, false).points());
+        assert_eq!(12, score_4_card_cribbage_hand([TWO_OF_CLUBS, SIX_OF_DIAMONDS, SIX_OF_HEARTS, SEVEN_OF_SPADES], SEVEN_OF_CLUBS, false).points());
+        assert_eq!(16, score_4_card_cribbage_hand([TWO_OF_CLUBS, SIX_OF_DIAMONDS, SEVEN_OF_HEARTS, SEVEN_OF_SPADES], EIGHT_OF_CLUBS, false).points());
+        assert_eq!(20, score_4_card_cribbage_hand([THREE_OF_CLUBS, THREE_OF_DIAMONDS, THREE_OF_HEARTS, THREE_OF_SPADES], SIX_OF_CLUBS, false).points());
+        assert_eq!(24, score_4_card_cribbage_hand([THREE_OF_CLUBS, THREE_OF_DIAMONDS, THREE_OF_HEARTS, THREE_OF_SPADES], NINE_OF_CLUBS, false).points());
+        assert_eq!(21, score_4_card_cribbage_hand([THREE_OF_CLUBS, THREE_OF_DIAMONDS, THREE_OF_HEARTS, FOUR_OF_SPADES], FIVE_OF_CLUBS, false).points());
+        assert_eq!(18, score_4_card_cribbage_hand([THREE_OF_CLUBS, THREE_OF_DIAMONDS, THREE_OF_HEARTS, SIX_OF_SPADES], SIX_OF_CLUBS, false).points());
+        assert_eq!(20, score_4_card_cribbage_hand([THREE_OF_CLUBS, THREE_OF_DIAMONDS, FOUR_OF_HEARTS, FOUR_OF_SPADES], FIVE_OF_CLUBS, false).points());
+        assert_eq!(20, score_4_card_cribbage_hand([THREE_OF_CLUBS, THREE_OF_DIAMONDS, FOUR_OF_HEARTS, FIVE_OF_SPADES], FIVE_OF_CLUBS, false).points());
+        assert_eq!(20, score_4_card_cribbage_hand([THREE_OF_CLUBS, THREE_OF_DIAMONDS, SIX_OF_HEARTS, SIX_OF_SPADES], SIX_OF_CLUBS, false).points());
+        assert_eq!(14, score_4_card_cribbage_hand([THREE_OF_CLUBS, THREE_OF_DIAMONDS, SIX_OF_HEARTS, SIX_OF_SPADES], NINE_OF_CLUBS, false).points());
+        assert_eq!(20, score_4_card_cribbage_hand([THREE_OF_CLUBS, FOUR_OF_DIAMONDS, FOUR_OF_HEARTS, FOUR_OF_SPADES], FOUR_OF_CLUBS, false).points());
+        assert_eq!(17, score_4_card_cribbage_hand([THREE_OF_CLUBS, FOUR_OF_DIAMONDS, FOUR_OF_HEARTS, FOUR_OF_SPADES], FIVE_OF_CLUBS, false).points());
+        assert_eq!(16, score_4_card_cribbage_hand([THREE_OF_CLUBS, FOUR_OF_DIAMONDS, FOUR_OF_HEARTS, FIVE_OF_SPADES], FIVE_OF_CLUBS, false).points());
+        assert_eq!(24, score_4_card_cribbage_hand([THREE_OF_CLUBS, SIX_OF_DIAMONDS, SIX_OF_HEARTS, SIX_OF_SPADES], SIX_OF_CLUBS, false).points());
+        assert_eq!(24, score_4_card_cribbage_hand([FOUR_OF_CLUBS, FOUR_OF_DIAMONDS, FOUR_OF_HEARTS, FOUR_OF_SPADES], SEVEN_OF_CLUBS, false).points());
+        assert_eq!(20, score_4_card_cribbage_hand([FOUR_OF_CLUBS, FOUR_OF_DIAMONDS, FOUR_OF_HEARTS, SEVEN_OF_SPADES], SEVEN_OF_CLUBS, false).points());
+        assert_eq!(24, score_4_card_cribbage_hand([FOUR_OF_CLUBS, FOUR_OF_DIAMONDS, FIVE_OF_HEARTS, SIX_OF_SPADES], SIX_OF_CLUBS, false).points());
+        assert_eq!(14, score_4_card_cribbage_hand([FOUR_OF_CLUBS, FOUR_OF_DIAMONDS, SEVEN_OF_HEARTS, SEVEN_OF_SPADES], SEVEN_OF_CLUBS, false).points());
+        assert_eq!(24, score_4_card_cribbage_hand([FOUR_OF_CLUBS, FIVE_OF_DIAMONDS, FIVE_OF_HEARTS, SIX_OF_SPADES], SIX_OF_CLUBS, false).points());
+        assert_eq!(21, score_4_card_cribbage_hand([FOUR_OF_CLUBS, FIVE_OF_DIAMONDS, SIX_OF_HEARTS, SIX_OF_SPADES], SIX_OF_CLUBS, false).points());
+        assert_eq!(23, score_4_card_cribbage_hand([FIVE_OF_CLUBS, FIVE_OF_DIAMONDS, FIVE_OF_HEARTS, FOUR_OF_SPADES], SIX_OF_CLUBS, false).points());
+        assert_eq!(22, score_4_card_cribbage_hand([FIVE_OF_CLUBS, FIVE_OF_DIAMONDS, FIVE_OF_HEARTS, TEN_OF_SPADES], TEN_OF_CLUBS, false).points());
+        assert_eq!(23, score_4_card_cribbage_hand([FIVE_OF_CLUBS, FIVE_OF_DIAMONDS, JACK_OF_HEARTS, JACK_OF_SPADES], FIVE_OF_SPADES, false).points());
+        assert_eq!(28, score_4_card_cribbage_hand([FIVE_OF_CLUBS, FIVE_OF_DIAMONDS, FIVE_OF_HEARTS, FIVE_OF_SPADES], TEN_OF_CLUBS, false).points());
+        assert_eq!(18, score_4_card_cribbage_hand([FIVE_OF_CLUBS, FIVE_OF_DIAMONDS, TEN_OF_HEARTS, JACK_OF_SPADES], QUEEN_OF_SPADES, false).points());
+        assert_eq!(17, score_4_card_cribbage_hand([FIVE_OF_CLUBS, FIVE_OF_DIAMONDS, TEN_OF_HEARTS, JACK_OF_SPADES], QUEEN_OF_CLUBS, false).points());
+        assert_eq!(21, score_4_card_cribbage_hand([FIVE_OF_CLUBS, JACK_OF_DIAMONDS, JACK_OF_HEARTS, JACK_OF_SPADES], FIVE_OF_HEARTS, false).points());
+        assert_eq!(29, score_4_card_cribbage_hand([FIVE_OF_CLUBS, JACK_OF_DIAMONDS, FIVE_OF_HEARTS, FIVE_OF_SPADES], FIVE_OF_DIAMONDS, false).points());
+        assert_eq!(20, score_4_card_cribbage_hand([SIX_OF_CLUBS, SIX_OF_DIAMONDS, NINE_OF_HEARTS, NINE_OF_SPADES], NINE_OF_CLUBS, false).points());
+        assert_eq!(20, score_4_card_cribbage_hand([SIX_OF_CLUBS, NINE_OF_DIAMONDS, NINE_OF_HEARTS, NINE_OF_SPADES], NINE_OF_CLUBS, false).points());
+        assert_eq!(20, score_4_card_cribbage_hand([SIX_OF_CLUBS, SIX_OF_DIAMONDS, SEVEN_OF_HEARTS, SEVEN_OF_SPADES], EIGHT_OF_CLUBS, false).points());
+        assert_eq!(16, score_4_card_cribbage_hand([SIX_OF_CLUBS, SEVEN_OF_DIAMONDS, EIGHT_OF_HEARTS, NINE_OF_SPADES], NINE_OF_CLUBS, false).points());
+        assert_eq!(20, score_4_card_cribbage_hand([SEVEN_OF_CLUBS, SEVEN_OF_DIAMONDS, SEVEN_OF_HEARTS, ACE_OF_SPADES], ACE_OF_CLUBS, false).points());
+        assert_eq!(21, score_4_card_cribbage_hand([SEVEN_OF_CLUBS, SEVEN_OF_DIAMONDS, SEVEN_OF_HEARTS, EIGHT_OF_SPADES], NINE_OF_CLUBS, false).points());
+        assert_eq!(21, score_4_card_cribbage_hand([SEVEN_OF_CLUBS, SEVEN_OF_DIAMONDS, SEVEN_OF_HEARTS, EIGHT_OF_SPADES], SIX_OF_CLUBS, false).points());
+        assert_eq!(20, score_4_card_cribbage_hand([SEVEN_OF_CLUBS, SEVEN_OF_DIAMONDS, SEVEN_OF_HEARTS, EIGHT_OF_SPADES], EIGHT_OF_CLUBS, false).points());
+        assert_eq!(20, score_4_card_cribbage_hand([SEVEN_OF_CLUBS, EIGHT_OF_DIAMONDS, EIGHT_OF_HEARTS, EIGHT_OF_SPADES], EIGHT_OF_CLUBS, false).points());
+        assert_eq!(24, score_4_card_cribbage_hand([SEVEN_OF_CLUBS, SEVEN_OF_DIAMONDS, EIGHT_OF_HEARTS, EIGHT_OF_SPADES], NINE_OF_CLUBS, false).points());
+        assert_eq!(20, score_4_card_cribbage_hand([SEVEN_OF_CLUBS, EIGHT_OF_DIAMONDS, EIGHT_OF_HEARTS, NINE_OF_SPADES], NINE_OF_CLUBS, false).points());
+    }
+
+    #[test]
+    fn pegging_scores() {
+        let score = score_pegging(&[ACE_OF_SPADES, TWO_OF_SPADES, THREE_OF_SPADES, FOUR_OF_SPADES, FIVE_OF_SPADES]);
+        assert_eq!(7, score.points());
+        assert_eq!("Fifteen two and five is seven", format!("{}", score));
+
+        let score = score_pegging(&[TEN_OF_HEARTS, FIVE_OF_CLUBS]);
+        assert_eq!(2, score.points());
+        assert_eq!("Fifteen for two", format!("{}", score));
+
+        let score = score_pegging(&[TEN_OF_HEARTS, FIVE_OF_CLUBS, TEN_OF_CLUBS]);
+        assert_eq!(0, score.points());
+        assert_eq!("", format!("{}", score));
+
+        let score = score_pegging(&[TEN_OF_HEARTS, FIVE_OF_CLUBS, TEN_OF_CLUBS, SIX_OF_DIAMONDS]);
+        assert_eq!(2, score.points());
+        assert_eq!("Thirty-one for two", format!("{}", score));
+    }
+}
index 8ec8795652bb89bcdef9f8ac47920ba7256ddf2e..d06ca9dfb288c85d1446a0b773028ae3067c2be2 100644 (file)
@@ -1,5 +1,6 @@
 mod action;
 mod chatroom;
+mod cribbage;
 mod filter;
 mod poker;
 mod whist;