Implemented hand and deck
This commit is contained in:
parent
77315c79b0
commit
ac25a1caea
8 changed files with 451 additions and 59 deletions
|
|
@ -5,3 +5,4 @@ edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
rand = "0.9.0"
|
||||||
|
|
|
||||||
122
api/src/card.rs
122
api/src/card.rs
|
|
@ -35,27 +35,35 @@ impl Card {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Constructor from rank and suit
|
// Constructor from rank and suit
|
||||||
pub fn from_rank_suit(rank: u8, suit: u8) -> Self {
|
pub fn from_rank_suit(rank: u8, suit: u8) -> Result<Self, &'static str> {
|
||||||
assert!(rank >= Self::TWO && rank <= Self::ACE, "Invalid rank");
|
if rank < Self::TWO || rank > Self::ACE {
|
||||||
assert!(suit < Self::NUM_SUITS, "Invalid suit");
|
return Err("Invalid rank");
|
||||||
Self((suit << 4) | (rank & 0xF))
|
}
|
||||||
|
if suit >= Self::NUM_SUITS {
|
||||||
|
return Err("Invalid suit");
|
||||||
|
}
|
||||||
|
Ok(Self((suit << 4) | (rank & 0xF)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Constructor from index (0..51)
|
// Constructor from index (0..51)
|
||||||
pub fn from_index(index: u8) -> Self {
|
pub fn from_index(index: u8) -> Result<Self, &'static str> {
|
||||||
assert!(index < Self::NUM_CARDS, "Invalid index");
|
if index >= Self::NUM_CARDS {
|
||||||
|
return Err("Invalid index");
|
||||||
|
}
|
||||||
let rank = (index % Self::NUM_RANKS) + Self::TWO;
|
let rank = (index % Self::NUM_RANKS) + Self::TWO;
|
||||||
let suit = index / Self::NUM_RANKS;
|
let suit = index / Self::NUM_RANKS;
|
||||||
Self::from_rank_suit(rank, suit)
|
Self::from_rank_suit(rank, suit)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Constructor from string (e.g., "As" for Ace of Spades)
|
// Constructor from string (e.g., "As" for Ace of Spades)
|
||||||
pub fn from_string(s: &str) -> Self {
|
pub fn from_string(s: &str) -> Result<Self, &'static str> {
|
||||||
assert!(s.len() == 2, "Invalid card string");
|
if s.len() != 2 {
|
||||||
|
return Err("Invalid card string");
|
||||||
|
}
|
||||||
let rank_char = s.chars().nth(0).unwrap();
|
let rank_char = s.chars().nth(0).unwrap();
|
||||||
let suit_char = s.chars().nth(1).unwrap();
|
let suit_char = s.chars().nth(1).unwrap();
|
||||||
let rank = Self::rank_from_char(rank_char);
|
let rank = Self::rank_from_char(rank_char)?;
|
||||||
let suit = Self::suit_from_char(suit_char);
|
let suit = Self::suit_from_char(suit_char)?;
|
||||||
Self::from_rank_suit(rank, suit)
|
Self::from_rank_suit(rank, suit)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -80,64 +88,64 @@ impl Card {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert rank to character (e.g., 14 -> 'A')
|
// Convert rank to character (e.g., 14 -> 'A')
|
||||||
pub fn rank_to_char(rank: u8) -> char {
|
pub fn rank_to_char(rank: u8) -> Result<char, &'static str> {
|
||||||
match rank {
|
match rank {
|
||||||
Self::TWO => '2',
|
Self::TWO => Ok('2'),
|
||||||
Self::THREE => '3',
|
Self::THREE => Ok('3'),
|
||||||
Self::FOUR => '4',
|
Self::FOUR => Ok('4'),
|
||||||
Self::FIVE => '5',
|
Self::FIVE => Ok('5'),
|
||||||
Self::SIX => '6',
|
Self::SIX => Ok('6'),
|
||||||
Self::SEVEN => '7',
|
Self::SEVEN => Ok('7'),
|
||||||
Self::EIGHT => '8',
|
Self::EIGHT => Ok('8'),
|
||||||
Self::NINE => '9',
|
Self::NINE => Ok('9'),
|
||||||
Self::TEN => 'T',
|
Self::TEN => Ok('T'),
|
||||||
Self::JACK => 'J',
|
Self::JACK => Ok('J'),
|
||||||
Self::QUEEN => 'Q',
|
Self::QUEEN => Ok('Q'),
|
||||||
Self::KING => 'K',
|
Self::KING => Ok('K'),
|
||||||
Self::ACE => 'A',
|
Self::ACE => Ok('A'),
|
||||||
_ => panic!("Invalid rank"),
|
_ => Err("Invalid rank"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert suit to character (e.g., 0 -> 's')
|
// Convert suit to character (e.g., 0 -> 's')
|
||||||
pub fn suit_to_char(suit: u8) -> char {
|
pub fn suit_to_char(suit: u8) -> Result<char, &'static str> {
|
||||||
match suit {
|
match suit {
|
||||||
Self::SPADES => 's',
|
Self::SPADES => Ok('s'),
|
||||||
Self::HEARTS => 'h',
|
Self::HEARTS => Ok('h'),
|
||||||
Self::DIAMONDS => 'd',
|
Self::DIAMONDS => Ok('d'),
|
||||||
Self::CLUBS => 'c',
|
Self::CLUBS => Ok('c'),
|
||||||
_ => panic!("Invalid suit"),
|
_ => Err("Invalid suit"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert rank character to rank (e.g., 'A' -> 14)
|
// Convert rank character to rank (e.g., 'A' -> 14)
|
||||||
pub fn rank_from_char(rank_char: char) -> u8 {
|
pub fn rank_from_char(rank_char: char) -> Result<u8, &'static str> {
|
||||||
match rank_char {
|
match rank_char {
|
||||||
'2' => Self::TWO,
|
'2' => Ok(Self::TWO),
|
||||||
'3' => Self::THREE,
|
'3' => Ok(Self::THREE),
|
||||||
'4' => Self::FOUR,
|
'4' => Ok(Self::FOUR),
|
||||||
'5' => Self::FIVE,
|
'5' => Ok(Self::FIVE),
|
||||||
'6' => Self::SIX,
|
'6' => Ok(Self::SIX),
|
||||||
'7' => Self::SEVEN,
|
'7' => Ok(Self::SEVEN),
|
||||||
'8' => Self::EIGHT,
|
'8' => Ok(Self::EIGHT),
|
||||||
'9' => Self::NINE,
|
'9' => Ok(Self::NINE),
|
||||||
'T' => Self::TEN,
|
'T' => Ok(Self::TEN),
|
||||||
'J' => Self::JACK,
|
'J' => Ok(Self::JACK),
|
||||||
'Q' => Self::QUEEN,
|
'Q' => Ok(Self::QUEEN),
|
||||||
'K' => Self::KING,
|
'K' => Ok(Self::KING),
|
||||||
'A' => Self::ACE,
|
'A' => Ok(Self::ACE),
|
||||||
_ => panic!("Invalid rank character"),
|
_ => Err("Invalid rank character"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert suit character to suit (e.g., 's' -> 0)
|
// Convert suit character to suit (e.g., 's' -> 0)
|
||||||
pub fn suit_from_char(suit_char: char) -> u8 {
|
pub fn suit_from_char(suit_char: char) -> Result<u8, &'static str> {
|
||||||
match suit_char {
|
match suit_char {
|
||||||
's' => Self::SPADES,
|
's' => Ok(Self::SPADES),
|
||||||
'h' => Self::HEARTS,
|
'h' => Ok(Self::HEARTS),
|
||||||
'd' => Self::DIAMONDS,
|
'd' => Ok(Self::DIAMONDS),
|
||||||
'c' => Self::CLUBS,
|
'c' => Ok(Self::CLUBS),
|
||||||
_ => panic!("Invalid suit character"),
|
_ => Err("Invalid suit character"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -147,8 +155,8 @@ impl std::fmt::Display for Card {
|
||||||
if !self.is_valid() {
|
if !self.is_valid() {
|
||||||
write!(f, "Invalid Card")
|
write!(f, "Invalid Card")
|
||||||
} else {
|
} else {
|
||||||
let rank_char = Self::rank_to_char(self.rank());
|
let rank_char = Self::rank_to_char(self.rank()).unwrap();
|
||||||
let suit_char = Self::suit_to_char(self.suit());
|
let suit_char = Self::suit_to_char(self.suit()).unwrap();
|
||||||
write!(f, "{}{}", rank_char, suit_char)
|
write!(f, "{}{}", rank_char, suit_char)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -160,7 +168,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_card_creation() {
|
fn test_card_creation() {
|
||||||
let card = Card::from_rank_suit(Card::ACE, Card::SPADES);
|
let card = Card::from_rank_suit(Card::ACE, Card::SPADES).unwrap();
|
||||||
assert_eq!(card.rank(), Card::ACE);
|
assert_eq!(card.rank(), Card::ACE);
|
||||||
assert_eq!(card.suit(), Card::SPADES);
|
assert_eq!(card.suit(), Card::SPADES);
|
||||||
assert_eq!(card.index(), 12); // Ace of Spades is index 12
|
assert_eq!(card.index(), 12); // Ace of Spades is index 12
|
||||||
|
|
@ -169,7 +177,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_card_from_string() {
|
fn test_card_from_string() {
|
||||||
let card = Card::from_string("As");
|
let card = Card::from_string("As").unwrap();
|
||||||
assert_eq!(card.rank(), Card::ACE);
|
assert_eq!(card.rank(), Card::ACE);
|
||||||
assert_eq!(card.suit(), Card::SPADES);
|
assert_eq!(card.suit(), Card::SPADES);
|
||||||
assert_eq!(card.to_string(), "As");
|
assert_eq!(card.to_string(), "As");
|
||||||
|
|
@ -177,7 +185,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_card_from_index() {
|
fn test_card_from_index() {
|
||||||
let card = Card::from_index(0);
|
let card = Card::from_index(0).unwrap();
|
||||||
assert_eq!(card.rank(), Card::TWO);
|
assert_eq!(card.rank(), Card::TWO);
|
||||||
assert_eq!(card.suit(), Card::SPADES);
|
assert_eq!(card.suit(), Card::SPADES);
|
||||||
assert_eq!(card.to_string(), "2s");
|
assert_eq!(card.to_string(), "2s");
|
||||||
|
|
|
||||||
175
api/src/deck.rs
Normal file
175
api/src/deck.rs
Normal file
|
|
@ -0,0 +1,175 @@
|
||||||
|
use rand::seq::SliceRandom;
|
||||||
|
use rand::SeedableRng;
|
||||||
|
use std::fmt;
|
||||||
|
use crate::card::Card;
|
||||||
|
use crate::hand::Hand;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct Deck {
|
||||||
|
cards: Vec<Card>,
|
||||||
|
dealt: Vec<Card>, // Cards that have been dealt
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deck {
|
||||||
|
pub const NUM_CARDS: usize = 52;
|
||||||
|
|
||||||
|
// Create a new, unshuffled deck
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let mut cards = Vec::with_capacity(Self::NUM_CARDS);
|
||||||
|
for suit in 0..4 {
|
||||||
|
for rank in Card::TWO..=Card::ACE {
|
||||||
|
cards.push(Card::from_rank_suit(rank, suit).unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Self {
|
||||||
|
cards,
|
||||||
|
dealt: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new deck with a specific shuffle seed
|
||||||
|
pub fn with_seed(seed: u64) -> Self {
|
||||||
|
let mut deck = Self::new();
|
||||||
|
deck.shuffle_with_seed(seed);
|
||||||
|
deck
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shuffle the deck using a random seed
|
||||||
|
pub fn shuffle(&mut self) {
|
||||||
|
self.cards.shuffle(&mut rand::rng());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shuffle the deck using a specific seed
|
||||||
|
pub fn shuffle_with_seed(&mut self, seed: u64) {
|
||||||
|
let mut rng = rand::rngs::StdRng::seed_from_u64(seed);
|
||||||
|
self.cards.shuffle(&mut rng);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deal the next card from the deck
|
||||||
|
pub fn deal(&mut self) -> Option<Card> {
|
||||||
|
if self.cards.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let card = self.cards.pop().unwrap();
|
||||||
|
self.dealt.push(card);
|
||||||
|
Some(card)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deal a random card from the deck
|
||||||
|
pub fn deal_random(&mut self) -> Option<Card> {
|
||||||
|
if self.cards.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let index = rand::random::<u8>() as usize % self.cards.len();
|
||||||
|
let card = self.cards.remove(index);
|
||||||
|
self.dealt.push(card);
|
||||||
|
Some(card)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset the deck (put all cards back)
|
||||||
|
pub fn reset(&mut self) {
|
||||||
|
self.cards.extend(self.dealt.drain(..));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if a card is still in the deck
|
||||||
|
pub fn in_deck(&self, card: Card) -> bool {
|
||||||
|
self.cards.contains(&card)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove a specific card from the deck
|
||||||
|
pub fn extract_card(&mut self, card: Card) -> Option<Card> {
|
||||||
|
if let Some(index) = self.cards.iter().position(|&c| c == card) {
|
||||||
|
Some(self.cards.remove(index))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove a specific card by index from the deck
|
||||||
|
pub fn extract_card_by_index(&mut self, index: u8) -> Option<Card> {
|
||||||
|
if let Some(pos) = self.cards.iter().position(|&c| c.index() == index) {
|
||||||
|
Some(self.cards.remove(pos))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove all cards in a hand from the deck
|
||||||
|
pub fn extract_hand(&mut self, hand: &Hand) {
|
||||||
|
for card in hand.get_card_array() {
|
||||||
|
self.extract_card_by_index(card);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the number of cards left in the deck
|
||||||
|
pub fn cards_left(&self) -> usize {
|
||||||
|
self.cards.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the top card (next card to be dealt)
|
||||||
|
pub fn get_top_card(&self) -> Option<Card> {
|
||||||
|
self.cards.last().copied()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the index of the top card
|
||||||
|
pub fn get_top_card_index(&self) -> Option<u8> {
|
||||||
|
self.get_top_card().map(|card| card.index())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a card at a specific index in the deck
|
||||||
|
pub fn get_card(&self, index: usize) -> Option<Card> {
|
||||||
|
self.cards.get(index).copied()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Deck {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "Deck ({} cards left)", self.cards_left())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_deck_creation() {
|
||||||
|
let deck = Deck::new();
|
||||||
|
assert_eq!(deck.cards_left(), Deck::NUM_CARDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_deck_shuffle() {
|
||||||
|
let mut deck = Deck::new();
|
||||||
|
deck.shuffle();
|
||||||
|
assert_eq!(deck.cards_left(), Deck::NUM_CARDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_deck_deal() {
|
||||||
|
let mut deck = Deck::new();
|
||||||
|
let card = deck.deal().unwrap();
|
||||||
|
assert_eq!(deck.cards_left(), Deck::NUM_CARDS - 1);
|
||||||
|
assert!(!deck.in_deck(card));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_deck_reset() {
|
||||||
|
let mut deck = Deck::new();
|
||||||
|
let card = deck.deal().unwrap();
|
||||||
|
deck.reset();
|
||||||
|
assert_eq!(deck.cards_left(), Deck::NUM_CARDS);
|
||||||
|
assert!(deck.in_deck(card));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_deck_extract_card() {
|
||||||
|
let mut deck = Deck::new();
|
||||||
|
let card = Card::from_string("As").unwrap();
|
||||||
|
deck.extract_card(card).unwrap();
|
||||||
|
assert_eq!(deck.cards_left(), Deck::NUM_CARDS - 1);
|
||||||
|
assert!(!deck.in_deck(card));
|
||||||
|
}
|
||||||
|
}
|
||||||
180
api/src/hand.rs
Normal file
180
api/src/hand.rs
Normal file
|
|
@ -0,0 +1,180 @@
|
||||||
|
use crate::card::Card;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct Hand {
|
||||||
|
cards: [Option<Card>; 7], // Up to 7 cards
|
||||||
|
size: usize, // Number of cards in the hand
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hand {
|
||||||
|
pub const MAX_CARDS: usize = 7;
|
||||||
|
|
||||||
|
// Create a new empty hand
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
cards: [None; Self::MAX_CARDS],
|
||||||
|
size: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a hand from a string representation (e.g., "As Ks Qs")
|
||||||
|
pub fn from_string(s: &str) -> Result<Self, &'static str> {
|
||||||
|
let mut hand = Self::new();
|
||||||
|
for card_str in s.split_whitespace() {
|
||||||
|
let card = Card::from_string(card_str)?;
|
||||||
|
hand.add_card(card)?;
|
||||||
|
}
|
||||||
|
Ok(hand)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a card to the hand
|
||||||
|
pub fn add_card(&mut self, card: Card) -> Result<(), &'static str> {
|
||||||
|
if self.size >= Self::MAX_CARDS {
|
||||||
|
return Err("Hand is full");
|
||||||
|
}
|
||||||
|
self.cards[self.size] = Some(card);
|
||||||
|
self.size += 1;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the last card in the hand
|
||||||
|
pub fn remove_card(&mut self) {
|
||||||
|
if self.size > 0 {
|
||||||
|
self.size -= 1;
|
||||||
|
self.cards[self.size] = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the card at a specific position (1-based indexing)
|
||||||
|
pub fn get_card(&self, pos: usize) -> Option<Card> {
|
||||||
|
if pos == 0 || pos > self.size {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
self.cards[pos - 1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the card index at a specific position (1-based indexing)
|
||||||
|
pub fn get_card_index(&self, pos: usize) -> Option<u8> {
|
||||||
|
self.get_card(pos).map(|card| card.index())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the last card in the hand
|
||||||
|
pub fn get_last_card(&self) -> Option<Card> {
|
||||||
|
if self.size == 0 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
self.cards[self.size - 1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the last card index in the hand
|
||||||
|
pub fn get_last_card_index(&self) -> Option<u8> {
|
||||||
|
self.get_last_card().map(|card| card.index())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the hand (remove all cards)
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
self.cards = [None; Self::MAX_CARDS];
|
||||||
|
self.size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort the hand in descending order by card index
|
||||||
|
pub fn sort(&mut self) {
|
||||||
|
self.cards[..self.size].sort_by(|a, b| {
|
||||||
|
let a_index = a.map(|card| card.index()).unwrap_or(0);
|
||||||
|
let b_index = b.map(|card| card.index()).unwrap_or(0);
|
||||||
|
b_index.cmp(&a_index) // Sort in descending order
|
||||||
|
}); }
|
||||||
|
|
||||||
|
// Check if the hand contains a specific card
|
||||||
|
pub fn contains(&self, card: Card) -> bool {
|
||||||
|
self.cards[..self.size].contains(&Some(card))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a string representation of the hand (e.g., "As Ks Qs")
|
||||||
|
pub fn to_string(&self) -> String {
|
||||||
|
self.cards[..self.size]
|
||||||
|
.iter()
|
||||||
|
.filter_map(|&card| card.map(|c| c.to_string()))
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(" ")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a string representation for flashing purposes
|
||||||
|
pub fn flashing_string(&self) -> String {
|
||||||
|
self.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the size of the hand
|
||||||
|
pub fn size(&self) -> usize {
|
||||||
|
self.size
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the array of card indexes (for LUT-based evaluators)
|
||||||
|
pub fn get_card_array(&self) -> Vec<u8> {
|
||||||
|
self.cards[..self.size]
|
||||||
|
.iter()
|
||||||
|
.filter_map(|&card| card.map(|c| c.index()))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::card::Card;
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hand_creation() {
|
||||||
|
let hand = Hand::new();
|
||||||
|
assert_eq!(hand.size(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_add_card() {
|
||||||
|
let mut hand = Hand::new();
|
||||||
|
let card = Card::from_string("As").unwrap();
|
||||||
|
hand.add_card(card).unwrap();
|
||||||
|
assert_eq!(hand.size(), 1);
|
||||||
|
assert_eq!(hand.get_card(1), Some(card));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_remove_card() {
|
||||||
|
let mut hand = Hand::new();
|
||||||
|
let card = Card::from_string("As").unwrap();
|
||||||
|
hand.add_card(card).unwrap();
|
||||||
|
hand.remove_card();
|
||||||
|
assert_eq!(hand.size(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hand_from_string() {
|
||||||
|
let hand = Hand::from_string("As Ks Qs").unwrap();
|
||||||
|
assert_eq!(hand.size(), 3);
|
||||||
|
assert_eq!(hand.get_card(1), Some(Card::from_string("As").unwrap()));
|
||||||
|
assert_eq!(hand.get_card(2), Some(Card::from_string("Ks").unwrap()));
|
||||||
|
assert_eq!(hand.get_card(3), Some(Card::from_string("Qs").unwrap()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hand_sort() {
|
||||||
|
let mut hand = Hand::from_string("2s As Ks").unwrap();
|
||||||
|
hand.sort();
|
||||||
|
assert_eq!(hand.get_card(1), Some(Card::from_string("As").unwrap()));
|
||||||
|
assert_eq!(hand.get_card(2), Some(Card::from_string("Ks").unwrap()));
|
||||||
|
assert_eq!(hand.get_card(3), Some(Card::from_string("2s").unwrap()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hand_sort_with_empty_slots() {
|
||||||
|
let mut hand = Hand::new();
|
||||||
|
hand.add_card(Card::from_string("2s").unwrap()).unwrap();
|
||||||
|
hand.add_card(Card::from_string("As").unwrap()).unwrap();
|
||||||
|
hand.add_card(Card::from_string("Ks").unwrap()).unwrap();
|
||||||
|
hand.sort();
|
||||||
|
assert_eq!(hand.get_card(1), Some(Card::from_string("As").unwrap()));
|
||||||
|
assert_eq!(hand.get_card(2), Some(Card::from_string("Ks").unwrap()));
|
||||||
|
assert_eq!(hand.get_card(3), Some(Card::from_string("2s").unwrap()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1 +1,8 @@
|
||||||
pub mod card;
|
pub mod card;
|
||||||
|
pub mod hand;
|
||||||
|
pub mod deck;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,7 @@ use poker_api::card::Card;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_card_integration() {
|
fn test_card_integration() {
|
||||||
let card = Card::from_string("As");
|
let card = Card::from_string("As").unwrap();
|
||||||
assert_eq!(card.to_string(), "As");
|
assert_eq!(card.to_string(), "As");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
9
api/tests/deck_tests.rs
Normal file
9
api/tests/deck_tests.rs
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
use poker_api::deck::Deck;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_deck_integration() {
|
||||||
|
let mut deck = Deck::new();
|
||||||
|
let card = deck.deal().unwrap();
|
||||||
|
assert_eq!(deck.cards_left(), 51);
|
||||||
|
assert!(!deck.in_deck(card));
|
||||||
|
}
|
||||||
11
api/tests/hand_test.rs
Normal file
11
api/tests/hand_test.rs
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
use poker_api::card::Card;
|
||||||
|
use poker_api::hand::Hand;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hand_integration() {
|
||||||
|
let mut hand = Hand::new();
|
||||||
|
hand.add_card(Card::from_string("As").unwrap()).unwrap();
|
||||||
|
hand.add_card(Card::from_string("Ks").unwrap()).unwrap();
|
||||||
|
assert_eq!(hand.size(), 2);
|
||||||
|
assert_eq!(hand.to_string(), "As Ks");
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue