Skip to content

Commit

Permalink
feat: deck of cards & table draw (#2)
Browse files Browse the repository at this point in the history
### Why?

To play the game we need a deck of cards. Ranked by values and suit. To
start off the game we also need players to draw a random card for the
dealer button.

### What's changed?
- Added cards
- Added deck of cards
- Tables can be created out of four players. Where the player who draws
the highest card starts at the north position (with their team m8 across
the table at south). The player who draw the highest card in the
opposite team starts at the east position.
  • Loading branch information
Mollemoll authored May 29, 2024
1 parent 7530b02 commit 2ab671a
Show file tree
Hide file tree
Showing 9 changed files with 432 additions and 3 deletions.
68 changes: 68 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ version = "0.1.0"
edition = "2021"

[dependencies]
rand = "0.8.5"
178 changes: 178 additions & 0 deletions src/card.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord)]
pub enum Suit {
Clubs,
Diamonds,
Hearts,
Spades,
}

impl Suit {
pub fn all() -> Vec<Suit> {
vec![
Suit::Clubs,
Suit::Diamonds,
Suit::Hearts,
Suit::Spades,
]
}
}

#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord)]
pub enum Rank {
Two,
Three,
Four,
Five,
Six,
Seven,
Eight,
Nine,
Ten,
Jack,
Queen,
King,
Ace,
}

impl Rank {
pub fn all() -> Vec<Rank> {
vec![
Rank::Two,
Rank::Three,
Rank::Four,
Rank::Five,
Rank::Six,
Rank::Seven,
Rank::Eight,
Rank::Nine,
Rank::Ten,
Rank::Jack,
Rank::Queen,
Rank::King,
Rank::Ace,
]
}
}

#[derive(Debug, Clone, PartialEq)]
pub struct Card {
suit: Suit,
rank: Rank,
}

impl Card {
pub fn new(suit: Suit, rank: Rank) -> Card {
Card { suit, rank }
}

pub fn suit(&self) -> &Suit {
&self.suit
}

pub fn rank(&self) -> &Rank {
&self.rank
}

pub fn compare_bridge_value(&self, other: &Card) -> std::cmp::Ordering {
// Compare the ranks
let rank_comparison = self.rank().cmp(other.rank());
// If the ranks are equal, compare the suits
if rank_comparison == std::cmp::Ordering::Equal {
self.suit().cmp(other.suit())
} else {
rank_comparison
}
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn new_ace_of_spades() {
let card = Card {
suit: Suit::Spades,
rank: Rank::Ace,
};
assert_eq!(*card.suit(), Suit::Spades);
assert_eq!(*card.rank(), Rank::Ace);
}

#[test]
fn suit() {
let card = Card::new(Suit::Hearts, Rank::Two);
assert_eq!(*card.suit(), Suit::Hearts);
}

#[test]
fn rank() {
let card = Card::new(Suit::Hearts, Rank::Two);
assert_eq!(*card.rank(), Rank::Two);
}

#[test]
fn ace_higher_than_king() {
let ace = Card::new(Suit::Spades, Rank::Ace);
let king = Card::new(Suit::Spades, Rank::King);

assert!(ace.rank() > king.rank());
}

#[test]
fn deuce_lower_than_three() {
let deuce = Card::new(Suit::Spades, Rank::Two);
let three = Card::new(Suit::Spades, Rank::Three);

assert!(deuce.rank() < three.rank());
}

#[test]
fn ace_of_spades_equal_to_ace_of_spades() {
let ace1 = Card::new(Suit::Spades, Rank::Ace);
let ace2 = Card::new(Suit::Spades, Rank::Ace);

assert_eq!(ace1, ace2);
}

#[test]
fn same_suits_equals() {
let card1 = Card::new(Suit::Hearts, Rank::Two);
let card2 = Card::new(Suit::Hearts, Rank::Three);

assert_eq!(card1.suit(), card2.suit());
}

#[test]
fn three_of_clubs_less_than_three_of_diamonds() {
let three_of_clubs = Card::new(Suit::Clubs, Rank::Three);
let three_of_diamonds = Card::new(Suit::Diamonds, Rank::Three);

assert_eq!(
three_of_clubs.compare_bridge_value(&three_of_diamonds),
std::cmp::Ordering::Less
);
}

#[test]
fn compare_bridge_value() {
let aces = vec![
Card::new(Suit::Diamonds, Rank::Ace),
Card::new(Suit::Hearts, Rank::Ace),
Card::new(Suit::Spades, Rank::Ace),
Card::new(Suit::Clubs, Rank::Ace),
];
let mut sorted_aces = aces.clone();
sorted_aces.sort_by(|a, b| a.compare_bridge_value(b));

assert_eq!(
sorted_aces,
vec![
Card::new(Suit::Clubs, Rank::Ace),
Card::new(Suit::Diamonds, Rank::Ace),
Card::new(Suit::Hearts, Rank::Ace),
Card::new(Suit::Spades, Rank::Ace),
],
);
}
}
67 changes: 67 additions & 0 deletions src/deck.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use crate::card::{
Card,
Suit,
Rank,
};

#[derive(Debug)]
pub struct Deck {
pub cards: Vec<Card>,
}

impl Deck {
pub fn new() -> Deck {
let mut cards = Vec::new();

for suit in Suit::all() {
for rank in Rank::all() {
cards.push(Card::new(suit, rank));
}
}

Deck { cards }
}

pub fn len(&self) -> usize {
self.cards.len()
}

pub fn shuffle(&mut self) {
use rand::seq::SliceRandom;
use rand::thread_rng;

self.cards.shuffle(&mut thread_rng());
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn new_deck_has_52_cards() {
let deck = Deck::new();
assert_eq!(deck.len(), 52);
}

#[test]
fn shuffled_deck_differs_from_new_deck() {
let mut deck = Deck::new();
let original = deck.cards.clone();

deck.shuffle();

assert_ne!(deck.cards, original);
}

#[test]
fn shuffled_decks_are_different() {
let mut deck1 = Deck::new();
let mut deck2 = Deck::new();

deck1.shuffle();
deck2.shuffle();

assert_ne!(deck1.cards, deck2.cards);
}
}
1 change: 1 addition & 0 deletions src/game.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::user::User;
use crate::game::lobby::Lobby;

mod lobby;
mod table;

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
struct Settings {
Expand Down
4 changes: 2 additions & 2 deletions src/game/lobby.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ use crate::errors::GameError;
use crate::game::{BidRound, Player, Settings, Team};
use crate::user::User;

#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Clone)]
pub(crate) struct Lobby<'a> {
pub(crate) settings: Settings,
pub(crate) players: Vec<Player<'a>>,
}

impl<'a> Lobby<'a> {
fn add_user(&mut self, user: &'a User) {
pub(crate) fn add_user(&mut self, user: &'a User) {
// Create player
let player = Player::build(
&user,
Expand Down
Loading

0 comments on commit 2ab671a

Please sign in to comment.