summaryrefslogtreecommitdiff
path: root/webapp/src/card.rs
diff options
context:
space:
mode:
Diffstat (limited to 'webapp/src/card.rs')
-rw-r--r--webapp/src/card.rs277
1 files changed, 0 insertions, 277 deletions
diff --git a/webapp/src/card.rs b/webapp/src/card.rs
deleted file mode 100644
index 621bae1..0000000
--- a/webapp/src/card.rs
+++ /dev/null
@@ -1,277 +0,0 @@
-use anyhow::anyhow;
-use rand::prelude::SliceRandom;
-use rand::Rng;
-use std::fmt;
-use strum::EnumCount;
-use strum::IntoEnumIterator;
-use strum_macros::EnumCount;
-use strum_macros::EnumIter;
-
-#[derive(PartialOrd, Ord, PartialEq, Eq, Clone, Copy, EnumIter, EnumCount)]
-pub enum Suit {
- Club,
- Diamond,
- Heart,
- Spade,
-}
-
-#[derive(PartialOrd, Ord, PartialEq, Eq, Clone, Copy, EnumIter)]
-pub enum Rank {
- Two = 2,
- Three,
- Four,
- Five,
- Six,
- Seven,
- Eight,
- Nine,
- Ten,
- Jack,
- Queen,
- King,
- Ace,
-}
-
-impl fmt::Display for Suit {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
- f.write_str(match self {
- Suit::Club => "♣",
- Suit::Diamond => "♢",
- Suit::Heart => "♡",
- Suit::Spade => "♠",
- })
- }
-}
-
-impl std::str::FromStr for Suit {
- type Err = anyhow::Error;
-
- fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
- match s.trim() {
- "♣" => Ok(Suit::Club),
- "C" => Ok(Suit::Club),
- "♢" => Ok(Suit::Diamond),
- "♦" => Ok(Suit::Diamond),
- "D" => Ok(Suit::Diamond),
- "♡" => Ok(Suit::Heart),
- "♥" => Ok(Suit::Heart),
- "H" => Ok(Suit::Heart),
- "♠" => Ok(Suit::Spade),
- "S" => Ok(Suit::Spade),
- _ => Err(anyhow!("invalid suit: {}", s)),
- }
- }
-}
-
-impl fmt::Debug for Suit {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
- write!(f, "{}", self)
- }
-}
-
-impl fmt::Display for Rank {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
- f.write_str(match self {
- Rank::Ace => "A",
- Rank::King => "K",
- Rank::Queen => "Q",
- Rank::Jack => "J",
- Rank::Ten => "10",
- Rank::Nine => "9",
- Rank::Eight => "8",
- Rank::Seven => "7",
- Rank::Six => "6",
- Rank::Five => "5",
- Rank::Four => "4",
- Rank::Three => "3",
- Rank::Two => "2",
- })
- }
-}
-
-impl fmt::Debug for Rank {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
- write!(f, "{}", self)
- }
-}
-
-impl std::str::FromStr for Rank {
- type Err = anyhow::Error;
-
- fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
- match s.trim().to_ascii_uppercase().as_str() {
- "A" => Ok(Rank::Ace),
- "K" => Ok(Rank::King),
- "Q" => Ok(Rank::Queen),
- "J" => Ok(Rank::Jack),
- "10" => Ok(Rank::Ten),
- "T" => Ok(Rank::Ten),
- "9" => Ok(Rank::Nine),
- "8" => Ok(Rank::Eight),
- "7" => Ok(Rank::Seven),
- "6" => Ok(Rank::Six),
- "5" => Ok(Rank::Five),
- "4" => Ok(Rank::Four),
- "3" => Ok(Rank::Three),
- "2" => Ok(Rank::Two),
- _ => Err(anyhow!("invalid rank: {}", s)),
- }
- }
-}
-
-#[derive(PartialEq, Eq, Clone, Copy)]
-pub struct Card(pub Suit, pub Rank);
-
-impl fmt::Display for Card {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
- let Card(suit, rank) = self;
- write!(f, "{}{}", suit, rank)
- }
-}
-
-impl fmt::Debug for Card {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
- write!(f, "{}", self)
- }
-}
-
-impl std::str::FromStr for Card {
- type Err = anyhow::Error;
-
- fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
- let stripped = s.replace(" ", "");
- let mut chars = stripped.chars();
- let suit = chars
- .next()
- .ok_or(anyhow!("missing parts: {}", s))?
- .to_string()
- .parse()?;
- let rank = chars.collect::<String>().parse()?;
- Ok(Card(suit, rank))
- }
-}
-
-fn make_deck() -> Vec<Card> {
- let mut result = vec![];
- for suit in Suit::iter() {
- for rank in Rank::iter() {
- result.push(Card(suit, rank));
- }
- }
- result
-}
-
-#[derive(Default, PartialEq, Eq, Copy, Clone)]
-pub enum RankOrder {
- #[default]
- Descending,
- Ascending,
-}
-
-pub fn sort_cards(suits: &[Suit; 4], ord: RankOrder, cards: &mut [Card]) {
- let mut score: [u8; Suit::COUNT] = [0; Suit::COUNT];
- for (i, suit) in suits.iter().enumerate() {
- score[*suit as usize] = i as u8;
- }
- cards.sort_by(|&Card(s1, r1), &Card(s2, r2)| {
- let order = {
- if s1 == s2 {
- r1.cmp(&r2)
- } else {
- score[s1 as usize].cmp(&score[s2 as usize])
- }
- };
- if ord == RankOrder::Descending {
- order.reverse()
- } else {
- order
- }
- });
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use log::info;
-
- #[test]
- fn sorting_cards() {
- let card = |s: &str| s.parse::<Card>().unwrap();
- assert_eq!([card("♥2"), card("♥3"), card("♥4"),], {
- let mut cards = [card("♥2"), card("♥4"), card("♥3")];
- sort_cards(
- &[Suit::Heart, Suit::Spade, Suit::Club, Suit::Diamond],
- RankOrder::Ascending,
- &mut cards,
- );
- cards
- });
- assert_eq!([card("♥A"), card("♥3"), card("♥2"),], {
- let mut cards = [card("♥2"), card("♥A"), card("♥3")];
- sort_cards(
- &[Suit::Heart, Suit::Spade, Suit::Club, Suit::Diamond],
- RankOrder::Descending,
- &mut cards,
- );
- cards
- });
- assert_eq!([card("♠A"), card("♥A"), card("♣A"), card("♦A"),], {
- let mut cards = [card("♣A"), card("♠A"), card("♥A"), card("♦A")];
- sort_cards(
- &[Suit::Diamond, Suit::Club, Suit::Heart, Suit::Spade],
- RankOrder::Descending,
- &mut cards,
- );
- cards
- });
- }
-
- #[test]
- fn string_conversion() {
- crate::tests::test_setup();
- info!("deck: {:?}", make_deck());
- assert_eq!(
- make_deck(),
- make_deck()
- .iter()
- .map(|card| format!("{}", card).parse().unwrap())
- .collect::<Vec<Card>>(),
- );
- }
-}
-
-#[derive(Debug, PartialEq, Eq, Clone)]
-pub struct Deal {
- pub north: Vec<Card>,
- pub west: Vec<Card>,
- pub south: Vec<Card>,
- pub east: Vec<Card>,
-}
-
-impl Deal {
- pub fn sort(&mut self, suits: &[Suit; 4], ord: RankOrder) {
- sort_cards(suits, ord, self.north.as_mut_slice());
- sort_cards(suits, ord, self.west.as_mut_slice());
- sort_cards(suits, ord, self.south.as_mut_slice());
- sort_cards(suits, ord, self.east.as_mut_slice());
- }
-}
-
-pub fn deal<R>(rng: &mut R) -> Deal
-where
- R: Rng,
-{
- let mut deck = make_deck();
- deck.shuffle(rng);
- let mut deck = deck.iter();
- let north = deck.by_ref().take(13).cloned().collect();
- let west = deck.by_ref().take(13).cloned().collect();
- let south = deck.by_ref().take(13).cloned().collect();
- let east = deck.by_ref().take(13).cloned().collect();
- Deal {
- north,
- west,
- south,
- east,
- }
-}