Skip to content

Commit

Permalink
Tweaks (#31)
Browse files Browse the repository at this point in the history
* added Standard52::pile_from_index
* Updated Rank weight
* added prime field to Rank for future work
* Added fmt::binary to Rank
* refactored Card constructors
* refactored Card index constructor a little more
* Added default Rank and Suit
* Improved Card doc
* Updated joker rank weight to be incremental
* Added mirror symbols to suit filter
* Added Pile.map_by_rank_count()
* Updated weight to u32
* Added Standard52::pile_from_index_validated()
* Refactored Standard52::pile_from_index_validated()
* Finished coverage for Standard52Set
* Card cleanup
* Standard52 cleanup
* More Card cleanup
* Bumped version
  • Loading branch information
folkengine authored Jan 5, 2022
1 parent d0b2ae4 commit 4514d8b
Show file tree
Hide file tree
Showing 18 changed files with 906 additions and 270 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "cardpack"
description = "Generic Deck of Cards"
version = "0.4.7"
version = "0.4.8"
authors = ["folkengine <gaoler@electronicpanopticon.com>"]
repository = "https://github.com/ContractBridge/cardpack.rs.git"
homepage = "https://github.com/ContractBridge/cardpack.rs"
Expand Down
1 change: 1 addition & 0 deletions clippy.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
msrv = "1.56.0"

cognitive-complexity-threshold = 30

7 changes: 7 additions & 0 deletions examples/standard52.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use cardpack::Named;

fn main() {
println!("Let's create a Standard 52 deck of cards:");
let standard52 = cardpack::Standard52::default();
Expand All @@ -9,6 +11,11 @@ fn main() {
println!("Let's display it with its short suit index:");
println!("{}\n", standard52.deck.short_suit_indexes_to_string());

println!("Let's print each card out with the count:");
for card in standard52.pack.cards().clone().into_iter() {
println!("{} {}", card.count(), card.index_default());
}

println!("Let's create a shuffled Standard 52 deck of cards:");
let standard52 = cardpack::Standard52::new_shuffled();
println!("{}\n", standard52);
Expand Down
103 changes: 54 additions & 49 deletions src/cards/card.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,24 @@ use crate::Named;
pub const BLANK: &str = "blank";

/// `Card` is the core struct in the library. A Card is made up of a Rank,
/// a Suit and weight, which is an integer that controls how a card is sorted
/// in a Pile or as a part of a Vector.
/// a `Suit`, `weight`, which is an integer that controls how a card is sorted
/// in a `Pile` or as a part of a `Vector`, and index, which is a short `String`
/// representation of the card, suitable for serialization in text format.
///
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Card {
/// Used by the Pile struct to sort Cards.
pub weight: isize,
pub weight: u32,
/// The identity indicator in the corner of a playing card, such as `AS` for ace of spades.
pub index: String,
pub suit: Suit,
pub rank: Rank,
}

impl Card {
/// Instantiates a new Card with the default weight as defined in the fluent
/// templates.
/// Instantiates a Card with the weight determined by the passed in Rank and Suit.
#[must_use]
pub fn new(rank: &'static str, suit: &'static str) -> Card {
let suit = Suit::new(suit);
let rank = Rank::new(rank);
pub fn new(rank: Rank, suit: Suit) -> Card {
let weight = Card::determine_weight(&suit, &rank);
let index = Card::determine_index(&suit, &rank);
Card {
Expand All @@ -39,18 +37,10 @@ impl Card {
}
}

/// Instantiates a Card with the weight determined by the passed in Rank and
/// Suit.
/// Instantiates a new Card with the default weight as defined in the fluent templates.
#[must_use]
pub fn new_from_structs(rank: Rank, suit: Suit) -> Card {
let weight = Card::determine_weight(&suit, &rank);
let index = Card::determine_index(&suit, &rank);
Card {
weight,
index,
suit,
rank,
}
pub fn from_index_strings(rank: &'static str, suit: &'static str) -> Card {
Card::new(Rank::new(rank), Suit::new(suit))
}

/// Returns a Symbol String for the Card.
Expand All @@ -76,7 +66,15 @@ impl Card {

#[must_use]
pub fn blank_card() -> Card {
Card::new(BLANK, BLANK)
Card::from_index_strings(BLANK, BLANK)
}

/// A unique index of a `Card` relative to other cards in a `Pile` prioritized by `Rank` and
/// then by `Suit`, such that a 2 of spades is lower than a 3 of clubs. While Card.weight
/// prioritizes by `Suit` and then by `Rank`.
#[must_use]
pub fn count(&self) -> u32 {
(self.suit.weight - 1) + (self.rank.weight * 4) + 1
}

/// A valid Card is one where the Rank and Suit are not blank.
Expand All @@ -94,14 +92,15 @@ impl Card {
}

/// Prioritizes sorting by Suit and then by Rank.
fn determine_weight(suit: &Suit, rank: &Rank) -> isize {
fn determine_weight(suit: &Suit, rank: &Rank) -> u32 {
(suit.weight * 1000) + rank.weight
}
}

/// Defaults to a blank `Card`.
impl Default for Card {
fn default() -> Card {
Card::new(BLANK, BLANK)
Card::from_index_strings(BLANK, BLANK)
}
}

Expand All @@ -128,7 +127,7 @@ impl Named for Card {
format!("{} {}", rank, suit)
}

fn default_weight(&self) -> isize {
fn default_weight(&self) -> u32 {
Card::determine_weight(&self.suit, &self.rank)
}
}
Expand All @@ -138,78 +137,84 @@ impl Named for Card {
mod card_tests {
use super::*;
use crate::fluent::named::{GERMAN, US_ENGLISH};
use crate::{ACE, BLANK_RANK, BLANK_SUIT, CLUBS, HEARTS, JACK, QUEEN, SPADES};
use crate::{ACE, BLANK_RANK, BLANK_SUIT, CLUBS, DIAMONDS, HEARTS, JACK, QUEEN, SPADES, TWO};
use std::cell::Cell;

// region impl tests

#[test]
fn new() {
let expected = Card {
weight: 4014,
weight: 4012,
index: "AS".to_string(),
rank: Rank::new(ACE),
suit: Suit::new(SPADES),
};

assert_eq!(expected, Card::new(ACE, SPADES));
assert_eq!(expected, Card::from_index_strings(ACE, SPADES));
}

#[test]
fn new_from_structs() {
let expected = Card {
weight: 4014,
weight: 4012,
index: "AS".to_string(),
rank: Rank::new(ACE),
suit: Suit::new(SPADES),
};

assert_eq!(
expected,
Card::new_from_structs(Rank::new(ACE), Suit::new(SPADES))
);
assert_eq!(expected, Card::new(Rank::new(ACE), Suit::new(SPADES)));
}

#[test]
fn count() {
assert_eq!(52, Card::from_index_strings(ACE, SPADES).count());
assert_eq!(1, Card::from_index_strings(TWO, CLUBS).count());
assert_eq!(2, Card::from_index_strings(TWO, DIAMONDS).count());
}

#[test]
fn index() {
let card = Card::new(QUEEN, CLUBS);
let card = Card::from_index_strings(QUEEN, CLUBS);

assert_eq!(card.index(&GERMAN), "DK".to_string());
}

#[test]
fn symbol() {
let card = Card::new(QUEEN, HEARTS);
let card = Card::from_index_strings(QUEEN, HEARTS);

assert_eq!(card.symbol(&GERMAN), "D♥".to_string());
}

#[test]
fn symbol_colorized() {
let card = Card::new(QUEEN, HEARTS);
let card = Card::from_index_strings(QUEEN, HEARTS);

assert_eq!(card.symbol_colorized(&GERMAN), "D♥".red().to_string());
}

#[test]
fn is_valid() {
assert!(Card::new(QUEEN, CLUBS).is_valid())
assert!(Card::from_index_strings(QUEEN, CLUBS).is_valid())
}

#[test]
fn is_valid__false() {
assert!(!Card::new("", "").is_valid());
assert!(!Card::new(QUEEN, BLANK_SUIT).is_valid());
assert!(!Card::new(BLANK_RANK, CLUBS).is_valid());
assert!(!Card::new(BLANK_RANK, BLANK_SUIT).is_valid());
assert!(!Card::new(" ", BLANK_SUIT).is_valid());
assert!(!Card::from_index_strings("", "").is_valid());
assert!(!Card::from_index_strings(QUEEN, BLANK_SUIT).is_valid());
assert!(!Card::from_index_strings(BLANK_RANK, CLUBS).is_valid());
assert!(!Card::from_index_strings(BLANK_RANK, BLANK_SUIT).is_valid());
assert!(!Card::from_index_strings(" ", BLANK_SUIT).is_valid());
}

#[test]
fn default() {
let card = Card::default();

assert_eq!(-1001, card.weight);
// println!("{:?}", card);

assert_eq!(0, card.weight);
assert_eq!("__".to_string(), card.index);
assert_eq!("__".to_string(), card.index_default());
assert_eq!("__".to_string(), card.symbol(&US_ENGLISH));
Expand All @@ -223,15 +228,15 @@ mod card_tests {

#[test]
fn named__name() {
let jack = Card::new(JACK, SPADES);
let jack = Card::from_index_strings(JACK, SPADES);

assert_eq!(&"JS".to_string(), jack.name());
}

#[test]
fn named__default_weight() {
let original = Card::new(ACE, SPADES);
let mut ace = Card::new(ACE, SPADES);
let original = Card::from_index_strings(ACE, SPADES);
let mut ace = Card::from_index_strings(ACE, SPADES);
assert_eq!(ace.weight, ace.default_weight());

let weight = ace.weight;
Expand All @@ -243,7 +248,7 @@ mod card_tests {

#[test]
fn named__index() {
let jack = Card::new(JACK, SPADES);
let jack = Card::from_index_strings(JACK, SPADES);

assert_eq!("JS".to_string(), jack.index(&US_ENGLISH));
assert_eq!("BS".to_string(), jack.index(&GERMAN));
Expand All @@ -252,7 +257,7 @@ mod card_tests {

#[test]
fn named__long() {
let ace = Card::new(ACE, SPADES);
let ace = Card::from_index_strings(ACE, SPADES);

assert_eq!("Ace Spades".to_string(), ace.long(&US_ENGLISH));
assert_eq!("Ass Spaten".to_string(), ace.long(&GERMAN));
Expand All @@ -263,21 +268,21 @@ mod card_tests {

#[test]
fn card_cell() {
let ace_of_spades = Card::new(ACE, SPADES);
let ace_of_spades = Card::from_index_strings(ACE, SPADES);
let blank = Card::default();
let cell = Cell::new(ace_of_spades.clone());

let aces = cell.take();

assert_eq!(Card::new(ACE, SPADES), aces);
assert_eq!(Card::from_index_strings(ACE, SPADES), aces);
assert_eq!(blank, cell.take());
assert_eq!(blank, cell.take());

cell.replace(ace_of_spades);

let aces = cell.take();

assert_eq!(Card::new(ACE, SPADES), aces);
assert_eq!(Card::from_index_strings(ACE, SPADES), aces);
assert_eq!(blank, cell.take());
assert_eq!(blank, cell.take());
}
Expand Down
8 changes: 8 additions & 0 deletions src/cards/card_error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#[derive(Debug, PartialEq)]
pub enum CardError {
InvalidCard,
InvalidCardCount,
InvalidIndex,
NotEnoughCards,
TooManyCards,
}
2 changes: 1 addition & 1 deletion src/cards/decks/bridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ impl BridgeBoard {
.map(|s| self.pack.cards().card_by_index(s.as_str()).unwrap().clone())
.collect();

Pile::new_from_vector(coll)
Pile::from_vector(coll)
}

fn splice_suit_in(s: &str, suit: char) -> Vec<String> {
Expand Down
3 changes: 2 additions & 1 deletion src/cards/decks/deck_error.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#[derive(Debug)]
#[derive(Debug, PartialEq)]
pub enum DeckError {
DuplicateCard,
InvalidIndex,
Incomplete,
PilePackMismatch,
Expand Down
1 change: 1 addition & 0 deletions src/cards/decks/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod bridge;
pub mod deck_error;
pub mod standard52;
pub mod standard52_set;
Loading

0 comments on commit 4514d8b

Please sign in to comment.