use cardpack::prelude::{BasicPile, DeckedBase, Pip, Standard52};
#[derive(Debug, Clone, Copy, Default)]
pub struct StandardRules;
impl GoFishRules for StandardRules {
fn name(&self) -> &'static str {
"Standard Go Fish"
}
fn deck(&self) -> BasicPile {
let mut pile = Standard52::basic_pile();
pile.shuffle();
pile
}
fn book_size(&self) -> usize {
4
}
fn initial_hand_size(&self, player_count: usize) -> usize {
if player_count <= 4 { 7 } else { 5 }
}
fn min_players(&self) -> usize {
2
}
fn max_players(&self) -> usize {
8
}
fn is_valid_ask(&self, hand: &BasicPile, rank: &Pip) -> bool {
hand.iter().any(|card| &card.rank == rank)
}
fn is_book(&self, cards: &BasicPile) -> bool {
if cards.len() != self.book_size() {
return false;
}
#[allow(clippy::indexing_slicing)]
let first_rank = cards.v()[0].rank;
cards.v().iter().all(|card| card.rank == first_rank)
}
}
use super::GoFishRules;
#[cfg(test)]
mod tests {
use super::*;
use cardpack::prelude::{BasicPile, DeckedBase, FrenchBasicCard, Standard52};
#[test]
fn test_standard_rules_name() {
assert_eq!(StandardRules.name(), "Standard Go Fish");
}
#[test]
fn test_standard_rules_deck_size() {
let deck = StandardRules.deck();
assert_eq!(deck.len(), 52);
}
#[test]
fn test_standard_rules_deck_is_shuffled() {
let rules = StandardRules;
let deck_a = rules.deck();
let deck_b = rules.deck();
assert_eq!(deck_a.len(), 52);
assert_ne!(
deck_a.v().iter().map(|c| c.index()).collect::<Vec<_>>(),
deck_b.v().iter().map(|c| c.index()).collect::<Vec<_>>(),
"two independently shuffled decks should almost never be identical"
);
}
#[test]
fn test_standard_rules_book_size() {
assert_eq!(StandardRules.book_size(), 4);
}
#[test]
fn test_standard_rules_initial_hand_size_small_game() {
assert_eq!(StandardRules.initial_hand_size(2), 7);
assert_eq!(StandardRules.initial_hand_size(3), 7);
assert_eq!(StandardRules.initial_hand_size(4), 7);
}
#[test]
fn test_standard_rules_initial_hand_size_large_game() {
assert_eq!(StandardRules.initial_hand_size(5), 5);
assert_eq!(StandardRules.initial_hand_size(8), 5);
}
#[test]
fn test_standard_rules_min_players() {
assert_eq!(StandardRules.min_players(), 2);
}
#[test]
fn test_standard_rules_max_players() {
assert_eq!(StandardRules.max_players(), 8);
}
#[test]
fn test_standard_rules_is_valid_ask_true() {
let pile = Standard52::basic_pile();
let ace_rank = pile.v()[0].rank;
assert!(StandardRules.is_valid_ask(&pile, &ace_rank));
}
#[test]
fn test_standard_rules_is_valid_ask_false_empty_hand() {
let empty = BasicPile::default();
let pile = Standard52::basic_pile();
let ace_rank = pile.v()[0].rank;
assert!(!StandardRules.is_valid_ask(&empty, &ace_rank));
}
#[test]
fn test_standard_rules_is_book_true() {
let pile = Standard52::basic_pile();
let ace_rank = pile.v()[0].rank;
let four_aces: BasicPile = pile
.iter()
.filter(|c| c.rank == ace_rank)
.copied()
.collect();
assert_eq!(four_aces.len(), 4);
assert!(StandardRules.is_book(&four_aces));
}
#[test]
fn test_standard_rules_is_book_false_wrong_count() {
let pile = Standard52::basic_pile();
let ace_rank = pile.v()[0].rank;
let three_aces: BasicPile = pile
.iter()
.filter(|c| c.rank == ace_rank)
.take(3)
.copied()
.collect();
assert!(!StandardRules.is_book(&three_aces));
}
#[test]
fn test_standard_rules_is_book_false_mixed_ranks() {
let mixed = BasicPile::from(vec![
FrenchBasicCard::ACE_SPADES,
FrenchBasicCard::ACE_HEARTS,
FrenchBasicCard::ACE_DIAMONDS,
FrenchBasicCard::KING_CLUBS,
]);
assert!(!StandardRules.is_book(&mixed));
}
#[test]
fn test_standard_rules_is_book_false_empty() {
let empty = BasicPile::default();
assert!(!StandardRules.is_book(&empty));
}
#[test]
fn test_standard_rules_is_valid_ask_partial_match() {
let hand = BasicPile::from(vec![
FrenchBasicCard::KING_SPADES,
FrenchBasicCard::DEUCE_HEARTS,
FrenchBasicCard::DEUCE_CLUBS,
FrenchBasicCard::DEUCE_DIAMONDS,
]);
let king_rank = FrenchBasicCard::KING_SPADES.rank;
let two_rank = FrenchBasicCard::DEUCE_HEARTS.rank;
let ace_rank = FrenchBasicCard::ACE_SPADES.rank;
assert!(StandardRules.is_valid_ask(&hand, &king_rank));
assert!(StandardRules.is_valid_ask(&hand, &two_rank));
assert!(!StandardRules.is_valid_ask(&hand, &ace_rank));
}
#[test]
fn test_standard_rules_trait_object_compiles() {
let rules: &dyn GoFishRules = &StandardRules;
assert_eq!(rules.name(), "Standard Go Fish");
assert_eq!(rules.book_size(), 4);
}
}