diff options
author | Kjetil Orbekk <kj@orbekk.com> | 2022-11-15 15:06:07 -0500 |
---|---|---|
committer | Kjetil Orbekk <kj@orbekk.com> | 2022-11-15 15:06:07 -0500 |
commit | 1f623cca3ea0937508b8c50f4c32a0972271e8f4 (patch) | |
tree | 3f5a36296ffc2afb1199cd65f9758c9667115450 /webapp/src/card.rs | |
parent | 8fa1b37bb705371bf5dee574f1f136019d3db9d1 (diff) |
Move shared bridge library code into `protocol` crate
Diffstat (limited to 'webapp/src/card.rs')
-rw-r--r-- | webapp/src/card.rs | 277 |
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, - } -} |