use std::mem;
use std::cmp;
use std::ascii::AsciiExt;
use std::fmt;
#[derive(PartialEq, PartialOrd, Eq, Ord, Debug, Clone, Copy, Hash)]
pub enum Value {
Two = 0,
Three = 1,
Four = 2,
Five = 3,
Six = 4,
Seven = 5,
Eight = 6,
Nine = 7,
Ten = 8,
Jack = 9,
Queen = 10,
King = 11,
Ace = 12,
}
const VALUES: [Value; 13] = [Value::Two,
Value::Three,
Value::Four,
Value::Five,
Value::Six,
Value::Seven,
Value::Eight,
Value::Nine,
Value::Ten,
Value::Jack,
Value::Queen,
Value::King,
Value::Ace];
impl Value {
pub fn from_u8(v: u8) -> Value {
unsafe { mem::transmute(cmp::min(v, Value::Ace as u8)) }
}
pub fn values() -> [Value; 13] {
VALUES
}
pub fn from_char(c: char) -> Option<Value> {
match c.to_ascii_uppercase() {
'A' => Some(Value::Ace),
'K' => Some(Value::King),
'Q' => Some(Value::Queen),
'J' => Some(Value::Jack),
'T' => Some(Value::Ten),
'9' => Some(Value::Nine),
'8' => Some(Value::Eight),
'7' => Some(Value::Seven),
'6' => Some(Value::Six),
'5' => Some(Value::Five),
'4' => Some(Value::Four),
'3' => Some(Value::Three),
'2' => Some(Value::Two),
_ => None,
}
}
pub fn to_char(&self) -> char {
match *self {
Value::Ace => 'A',
Value::King => 'K',
Value::Queen => 'Q',
Value::Jack => 'J',
Value::Ten => 'T',
Value::Nine => '9',
Value::Eight => '8',
Value::Seven => '7',
Value::Six => '6',
Value::Five => '5',
Value::Four => '4',
Value::Three => '3',
Value::Two => '2',
}
}
pub fn gap(&self, other: &Value) -> u8 {
let min = cmp::min(*self as u8, *other as u8);
let max = cmp::max(*self as u8, *other as u8);
max - min
}
}
#[derive(PartialEq, PartialOrd, Eq, Ord, Debug, Clone, Copy, Hash)]
pub enum Suit {
Spade = 0,
Club = 1,
Heart = 2,
Diamond = 3,
}
const SUITS: [Suit; 4] = [Suit::Spade, Suit::Club, Suit::Heart, Suit::Diamond];
impl Suit {
pub fn suits() -> [Suit; 4] {
SUITS
}
pub fn from_u8(s: u8) -> Suit {
unsafe { mem::transmute(cmp::min(s, Suit::Diamond as u8)) }
}
pub fn from_char(s: char) -> Option<Suit> {
match s.to_ascii_lowercase() {
'd' => Some(Suit::Diamond),
's' => Some(Suit::Spade),
'h' => Some(Suit::Heart),
'c' => Some(Suit::Club),
_ => None,
}
}
pub fn to_char(&self) -> char {
match *self {
Suit::Diamond => 'd',
Suit::Spade => 's',
Suit::Heart => 'h',
Suit::Club => 'c',
}
}
}
#[derive(PartialEq, PartialOrd, Eq, Ord, Debug, Clone, Copy, Hash)]
pub struct Card {
pub value: Value,
pub suit: Suit,
}
impl fmt::Display for Card {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}{}", self.value.to_char(), self.suit.to_char())
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::mem;
#[test]
fn test_constructor() {
let c = Card {
value: Value::Three,
suit: Suit::Spade,
};
assert_eq!(Suit::Spade, c.suit);
assert_eq!(Value::Three, c.value);
}
#[test]
fn test_compare() {
let c1 = Card {
value: Value::Three,
suit: Suit::Spade,
};
let c2 = Card {
value: Value::Four,
suit: Suit::Spade,
};
let c3 = Card {
value: Value::Four,
suit: Suit::Club,
};
assert!(c1 == c1);
assert!(c1 < c2);
assert!(c2 > c1);
assert!(c3 > c2);
}
#[test]
fn test_value_cmp() {
assert!(Value::Two < Value::Ace);
assert!(Value::King < Value::Ace);
assert_eq!(Value::Two, Value::Two);
}
#[test]
fn test_from_u8() {
assert_eq!(Value::Two, Value::from_u8(0));
assert_eq!(Value::Ace, Value::from_u8(12));
}
#[test]
fn test_size_card() {
assert!(mem::size_of::<Card>() <= 2);
}
#[test]
fn test_size_suit() {
assert!(mem::size_of::<Suit>() <= 1);
}
#[test]
fn test_size_value() {
assert!(mem::size_of::<Value>() <= 1);
}
#[test]
fn test_gap() {
assert!(1 == Value::Ace.gap(&Value::King));
assert!(0 == Value::Ace.gap(&Value::Ace));
assert!(0 == Value::Two.gap(&Value::Two));
assert!(1 == Value::Two.gap(&Value::Three));
assert!(1 == Value::Three.gap(&Value::Two));
assert!(12 == Value::Ace.gap(&Value::Two));
assert!(12 == Value::Two.gap(&Value::Ace));
}
}