use rand::{thread_rng, Rng, IsaacRng, SeedableRng};
use std::str::FromStr;
use std::num::Wrapping;
use std::string::ToString;
#[derive(PartialEq,Clone,Copy,Debug,Serialize,Deserialize)]
#[repr(u32)]
pub enum Suit {
Heart = 1 << 0,
Spade = 1 << 8,
Diamond = 1 << 16,
Club = 1 << 24,
}
impl Suit {
pub fn from_n(n: u32) -> Self {
match n {
0 => Suit::Heart,
1 => Suit::Spade,
2 => Suit::Diamond,
3 => Suit::Club,
other => panic!("bad suit number: {}", other),
}
}
pub fn to_string(self) -> String {
match self {
Suit::Heart => "♥",
Suit::Spade => "♠",
Suit::Diamond => "♦",
Suit::Club => "♣",
}
.to_owned()
}
}
impl FromStr for Suit {
type Err = String;
fn from_str(s: &str) -> Result<Self, String> {
match s {
"H" | "h" | "heart" | "Suit::Heart" | "Heart" => Ok(Suit::Heart),
"C" | "c" | "club" | "Suit::Club" | "Club" => Ok(Suit::Club),
"S" | "s" | "spade" | "Suit::Spade" | "Spade" => Ok(Suit::Spade),
"D" | "d" | "diamond" | "Suit::Diamond" | "Diamond" => Ok(Suit::Diamond),
_ => Err(format!("invalid suit: {}", s)),
}
}
}
#[derive(PartialEq,Clone,Copy,Debug)]
#[repr(u32)]
pub enum Rank {
Rank7 = 1 << 0,
Rank8 = 1 << 1,
Rank9 = 1 << 2,
RankJ = 1 << 3,
RankQ = 1 << 4,
RankK = 1 << 5,
RankX = 1 << 6,
RankA = 1 << 7,
}
const RANK_MASK: u32 = 255;
impl Rank {
pub fn from_n(n: u32) -> Self {
match n {
0 => Rank::Rank7,
1 => Rank::Rank8,
2 => Rank::Rank9,
3 => Rank::RankJ,
4 => Rank::RankQ,
5 => Rank::RankK,
6 => Rank::RankX,
7 => Rank::RankA,
other => panic!("invalid rank number: {}", other),
}
}
fn from_discriminant(rank: u32) -> Self {
match rank {
1 => Rank::Rank7,
2 => Rank::Rank8,
4 => Rank::Rank9,
8 => Rank::RankJ,
16 => Rank::RankQ,
32 => Rank::RankK,
64 => Rank::RankX,
128 => Rank::RankA,
other => panic!("invalid rank discrimant: {}", other),
}
}
pub fn to_string(self) -> String {
match self {
Rank::Rank7 => "7",
Rank::Rank8 => "8",
Rank::Rank9 => "9",
Rank::RankJ => "J",
Rank::RankQ => "Q",
Rank::RankK => "K",
Rank::RankX => "X",
Rank::RankA => "A",
}
.to_owned()
}
}
#[derive(PartialEq,Clone,Copy,Debug,Serialize,Deserialize)]
pub struct Card(u32);
impl Card {
pub fn id(self) -> u32 {
let mut i = 0;
let Card(mut v) = self;
while v != 0 {
i += 1;
v = v >> 1;
}
i - 1
}
pub fn from_id(id: u32) -> Self {
if id > 31 {
panic!("invalid card id");
}
Card(1 << id)
}
pub fn rank(self) -> Rank {
let suit = self.suit();
let Card(v) = self;
Rank::from_discriminant(v / suit as u32)
}
pub fn suit(self) -> Suit {
let Card(n) = self;
if n < Suit::Spade as u32 {
Suit::Heart
} else if n < Suit::Diamond as u32 {
Suit::Spade
} else if n < Suit::Club as u32 {
Suit::Diamond
} else {
Suit::Club
}
}
pub fn to_string(self) -> String {
let r = self.rank();
let s = self.suit();
r.to_string() + &s.to_string()
}
pub fn new(suit: Suit, rank: Rank) -> Self {
Card(suit as u32 * rank as u32)
}
}
#[derive(PartialEq,Clone,Copy,Debug,Serialize,Deserialize)]
pub struct Hand(u32);
impl Hand {
pub fn new() -> Self {
Hand(0)
}
pub fn add(&mut self, card: Card) -> &mut Hand {
self.0 |= card.0;
self
}
pub fn remove(&mut self, card: Card) {
self.0 &= !card.0;
}
pub fn clean(&mut self) {
*self = Hand::new();
}
pub fn has(self, card: Card) -> bool {
(self.0 & card.0) != 0
}
pub fn has_any(self, suit: Suit) -> bool {
(self.0 & (RANK_MASK * suit as u32)) != 0
}
pub fn is_empty(self) -> bool {
self.0 == 0
}
pub fn get_card(self) -> Card {
if self.is_empty() {
return Card(0);
}
let Hand(h) = self;
let n = Wrapping(h ^ (h - 1)) + Wrapping(1);
if n.0 == 0 {
Card::from_id(31)
} else {
Card(n.0 >> 1)
}
}
pub fn list(self) -> Vec<Card> {
let mut cards = Vec::new();
let mut h = self;
while !h.is_empty() {
let c = h.get_card();
h.remove(c);
cards.push(c);
}
cards
}
pub fn size(self) -> usize {
self.list().len()
}
}
impl ToString for Hand {
fn to_string(&self) -> String {
let mut s = "[".to_owned();
for c in &(*self).list() {
s = s + &c.to_string();
s = s + ",";
}
s + "]"
}
}
pub struct Deck {
cards: Vec<Card>,
}
impl Deck {
pub fn new() -> Self {
let mut d = Deck { cards: Vec::with_capacity(32) };
for i in 0..32 {
d.cards.push(Card::from_id(i));
}
d
}
pub fn shuffle(&mut self) {
self.shuffle_from(thread_rng());
}
pub fn shuffle_seeded(&mut self, seed: &[u32]) {
let mut rng = IsaacRng::new_unseeded();
rng.reseed(seed);
self.shuffle_from(rng);
}
fn shuffle_from<RNG: Rng>(&mut self, mut rng: RNG) {
rng.shuffle(&mut self.cards[..]);
}
pub fn draw(&mut self) -> Card {
self.cards.pop().expect("deck is empty")
}
pub fn is_empty(&self) -> bool {
self.cards.is_empty()
}
pub fn len(&self) -> usize {
self.cards.len()
}
pub fn deal_each(&mut self, hands: &mut [Hand; 4], n: usize) {
if self.len() < 4 * n {
panic!("Deck has too few cards!");
}
for hand in hands.iter_mut() {
for _ in 0..n {
hand.add(self.draw());
}
}
}
}
impl ToString for Deck {
fn to_string(&self) -> String {
let mut s = "[".to_owned();
for c in &self.cards {
s = s + &c.to_string();
s = s + ",";
}
s + "]"
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_cards() {
for i in 0..32 {
let card = Card::from_id(i);
assert!(i == card.id());
}
for s in 0..4 {
let suit = Suit::from_n(s);
for r in 0..8 {
let rank = Rank::from_n(r);
let card = Card::new(suit, rank);
assert!(card.rank() == rank);
assert!(card.suit() == suit);
}
}
}
#[test]
fn test_hand() {
let mut hand = Hand::new();
let cards: Vec<Card> = vec![
Card::new(Suit::Heart, Rank::Rank7),
Card::new(Suit::Heart, Rank::Rank8),
Card::new(Suit::Spade, Rank::Rank9),
Card::new(Suit::Spade, Rank::RankJ),
Card::new(Suit::Club, Rank::RankQ),
Card::new(Suit::Club, Rank::RankK),
Card::new(Suit::Diamond, Rank::RankX),
Card::new(Suit::Diamond, Rank::RankA),
];
assert!(hand.is_empty());
for card in cards.iter() {
assert!(!hand.has(*card));
hand.add(*card);
assert!(hand.has(*card));
}
assert!(hand.size() == cards.len());
for card in cards.iter() {
assert!(hand.has(*card));
hand.remove(*card);
assert!(!hand.has(*card));
}
}
#[test]
fn test_deck() {
let mut deck = Deck::new();
deck.shuffle();
assert!(deck.len() == 32);
let mut count = [0; 32];
while !deck.is_empty() {
let card = deck.draw();
count[card.id() as usize] += 1;
}
for c in count.iter() {
assert!(*c == 1);
}
}
}
#[cfg(feature="use_bench")]
mod benchs {
use test::Bencher;
use deal_seeded_hands;
#[bench]
fn bench_deal(b: &mut Bencher) {
let seed = &[1, 2, 3, 4, 5];
b.iter(|| {
deal_seeded_hands(seed);
});
}
#[bench]
fn bench_list_hand(b: &mut Bencher) {
let seed = &[1, 2, 3, 4, 5];
let hands = deal_seeded_hands(seed);
b.iter(|| {
for hand in hands.iter() {
hand.list().len();
}
});
}
#[bench]
fn bench_del_add_check(b: &mut Bencher) {
let seed = &[1, 2, 3, 4, 5];
let hands = deal_seeded_hands(seed);
let cards: Vec<_> = hands.iter().map(|h| h.list()).collect();
b.iter(|| {
let mut hands = hands.clone();
for (hand, cards) in hands.iter_mut().zip(cards.iter()) {
for c in cards.iter() {
hand.remove(*c);
}
}
for (hand, cards) in hands.iter_mut().zip(cards.iter()) {
for c in cards.iter() {
hand.add(*c);
}
}
for (hand, cards) in hands.iter_mut().zip(cards.iter()) {
for c in cards.iter() {
if !hand.has(*c) {
panic!("Error!");
}
}
}
});
}
}