///|
/// A validated standard-deck card. Construct with parse_card.
pub struct Card {
priv id : Int
} derive(Eq, Debug)
///|
/// Parse a two-character ASCII card, e.g. As, Th, 2c (case sensitive).
pub fn parse_card(text : String) -> Result[Card, String] {
let ranks = ["2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K", "A"]
let suits = ["c", "d", "h", "s"]
for r in 0..<13 {
for s in 0..<4 {
if text == ranks[r] + suits[s] {
return Ok({ id: r * 4 + s, })
}
}
}
Err("Invalid card: " + text + ". Expected As, Th, 2c, etc.")
}
///|
/// Parse space-separated cards and reject duplicate physical cards.
pub fn parse_cards(text : String) -> Result[Array[Card], String] {
let cards = []
for part in text.split(" ") {
let token = part.to_owned()
if token == "" {
continue
}
match parse_card(token) {
Ok(card) => cards.push(card)
Err(e) => return Err(e)
}
}
match validate_unique(cards) {
Some(e) => Err(e)
None => Ok(cards)
}
}
///|
/// Render a card in the canonical ASCII notation.
pub fn Card::text(self : Card) -> String {
let ranks = ["2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K", "A"]
let suits = ["c", "d", "h", "s"]
ranks[self.id / 4] + suits[self.id % 4]
}
///|
fn validate_unique(cards : Array[Card]) -> String? {
let seen = Array::make(52, false)
for card in cards {
if seen[card.id] {
return Some("Duplicate card: " + card.text())
}
seen[card.id] = true
}
None
}