Initial setup of API test

This commit is contained in:
Jan-Peter von Hunnius 2025-02-13 11:53:22 +01:00
parent 4b516c699f
commit 52deab3a48
3 changed files with 200 additions and 0 deletions

192
api/src/card.rs Normal file
View file

@ -0,0 +1,192 @@
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Card(u8);
impl Card {
// Constants for suits
pub const SPADES: u8 = 0;
pub const HEARTS: u8 = 1;
pub const DIAMONDS: u8 = 2;
pub const CLUBS: u8 = 3;
// Constants for ranks
pub const TWO: u8 = 2;
pub const THREE: u8 = 3;
pub const FOUR: u8 = 4;
pub const FIVE: u8 = 5;
pub const SIX: u8 = 6;
pub const SEVEN: u8 = 7;
pub const EIGHT: u8 = 8;
pub const NINE: u8 = 9;
pub const TEN: u8 = 10;
pub const JACK: u8 = 11;
pub const QUEEN: u8 = 12;
pub const KING: u8 = 13;
pub const ACE: u8 = 14;
// Special constants
pub const BAD_CARD: u8 = 255;
pub const NUM_SUITS: u8 = 4;
pub const NUM_RANKS: u8 = 13;
pub const NUM_CARDS: u8 = 52;
// Constructor for an empty/invalid card
pub fn new() -> Self {
Self(Self::BAD_CARD)
}
// Constructor from rank and suit
pub fn from_rank_suit(rank: u8, suit: u8) -> Self {
assert!(rank >= Self::TWO && rank <= Self::ACE, "Invalid rank");
assert!(suit < Self::NUM_SUITS, "Invalid suit");
Self((suit << 4) | (rank & 0xF))
}
// Constructor from index (0..51)
pub fn from_index(index: u8) -> Self {
assert!(index < Self::NUM_CARDS, "Invalid index");
let rank = (index % Self::NUM_RANKS) + Self::TWO;
let suit = index / Self::NUM_RANKS;
Self::from_rank_suit(rank, suit)
}
// Constructor from string (e.g., "As" for Ace of Spades)
pub fn from_string(s: &str) -> Self {
assert!(s.len() == 2, "Invalid card string");
let rank_char = s.chars().nth(0).unwrap();
let suit_char = s.chars().nth(1).unwrap();
let rank = Self::rank_from_char(rank_char);
let suit = Self::suit_from_char(suit_char);
Self::from_rank_suit(rank, suit)
}
// Get the rank of the card
pub fn rank(&self) -> u8 {
self.0 & 0xF
}
// Get the suit of the card
pub fn suit(&self) -> u8 {
(self.0 >> 4) & 0x3
}
// Get the index of the card (0..51)
pub fn index(&self) -> u8 {
(self.suit() * Self::NUM_RANKS) + (self.rank() - Self::TWO)
}
// Check if the card is valid
pub fn is_valid(&self) -> bool {
self.0 != Self::BAD_CARD
}
// Convert rank to character (e.g., 14 -> 'A')
pub fn rank_to_char(rank: u8) -> char {
match rank {
Self::TWO => '2',
Self::THREE => '3',
Self::FOUR => '4',
Self::FIVE => '5',
Self::SIX => '6',
Self::SEVEN => '7',
Self::EIGHT => '8',
Self::NINE => '9',
Self::TEN => 'T',
Self::JACK => 'J',
Self::QUEEN => 'Q',
Self::KING => 'K',
Self::ACE => 'A',
_ => panic!("Invalid rank"),
}
}
// Convert suit to character (e.g., 0 -> 's')
pub fn suit_to_char(suit: u8) -> char {
match suit {
Self::SPADES => 's',
Self::HEARTS => 'h',
Self::DIAMONDS => 'd',
Self::CLUBS => 'c',
_ => panic!("Invalid suit"),
}
}
// Convert rank character to rank (e.g., 'A' -> 14)
pub fn rank_from_char(rank_char: char) -> u8 {
match rank_char {
'2' => Self::TWO,
'3' => Self::THREE,
'4' => Self::FOUR,
'5' => Self::FIVE,
'6' => Self::SIX,
'7' => Self::SEVEN,
'8' => Self::EIGHT,
'9' => Self::NINE,
'T' => Self::TEN,
'J' => Self::JACK,
'Q' => Self::QUEEN,
'K' => Self::KING,
'A' => Self::ACE,
_ => panic!("Invalid rank character"),
}
}
// Convert suit character to suit (e.g., 's' -> 0)
pub fn suit_from_char(suit_char: char) -> u8 {
match suit_char {
's' => Self::SPADES,
'h' => Self::HEARTS,
'd' => Self::DIAMONDS,
'c' => Self::CLUBS,
_ => panic!("Invalid suit character"),
}
}
}
impl std::fmt::Display for Card {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if !self.is_valid() {
write!(f, "Invalid Card")
} else {
let rank_char = Self::rank_to_char(self.rank());
let suit_char = Self::suit_to_char(self.suit());
write!(f, "{}{}", rank_char, suit_char)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_card_creation() {
let card = Card::from_rank_suit(Card::ACE, Card::SPADES);
assert_eq!(card.rank(), Card::ACE);
assert_eq!(card.suit(), Card::SPADES);
assert_eq!(card.index(), 12); // Ace of Spades is index 12
assert!(card.is_valid());
}
#[test]
fn test_card_from_string() {
let card = Card::from_string("As");
assert_eq!(card.rank(), Card::ACE);
assert_eq!(card.suit(), Card::SPADES);
assert_eq!(card.to_string(), "As");
}
#[test]
fn test_card_from_index() {
let card = Card::from_index(0);
assert_eq!(card.rank(), Card::TWO);
assert_eq!(card.suit(), Card::SPADES);
assert_eq!(card.to_string(), "2s");
}
#[test]
fn test_invalid_card() {
let card = Card::new();
assert!(!card.is_valid());
assert_eq!(card.to_string(), "Invalid Card");
}
}

1
api/src/lib.rs Normal file
View file

@ -0,0 +1 @@
pub mod card;