Skip to content

Commit

Permalink
Implemented Four of a Kind rank - Poker
Browse files Browse the repository at this point in the history
  • Loading branch information
davassi committed Sep 16, 2023
1 parent 53dce72 commit a1d96d7
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 17 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,16 @@ Player 2: 10♠️ 8♥️ 4♥️ 3♥️ 2♠️
4. Celebrate the winner:
The winner is Player 1

```

At programmatic level, there are some handy macros (newcard!, hand!, assert_rank!) implemented to deal with cards, hands and ranks. Example:

```rust
assert_rank!(hand!["Ad","Kd","Qd","Jd","10d"], Rank::RoyalFlush);
```

or

```rust
assert_eq!(newcard!["Ah"], Card::new(14, Suit::Hearts));
```
35 changes: 22 additions & 13 deletions src/card.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,10 @@ impl Ord for Card {
pub enum CardError {
#[error("the card string is not the correct length")]
InvalidLength,

#[error("the card value is invalid")]
InvalidValue,

#[error("the card suit is invalid")]
InvalidSuit,
}
Expand All @@ -71,7 +71,6 @@ impl TryFrom<&str> for Card {
type Error = CardError;

fn try_from(card: &str) -> Result<Self, Self::Error> {

if card.len() != 2 && card.len() != 3 {
return Err(CardError::InvalidLength);
}
Expand All @@ -89,7 +88,7 @@ impl TryFrom<&str> for Card {
_ => return Err(CardError::InvalidValue),
};

let suit = chars[if val == 10 {2} else {1}];
let suit = chars[if val == 10 { 2 } else { 1 }];

let suit = match suit.to_ascii_lowercase() {
'h' => Suit::Hearts,
Expand Down Expand Up @@ -151,6 +150,7 @@ pub enum Rank {
}

/// An array of 5 cards compose a [`Hand`].
///
#[derive(Debug, PartialEq, Clone, Eq)]
pub struct Hand {
hand: [Card; 5],
Expand All @@ -177,6 +177,8 @@ impl Hand {
}
}

/// A vector of 52 cards compose a [`Deck`], plus an iterator to help getting (/borrowing) cards out of the deck.
///
#[derive(Debug, PartialEq, Clone)]
pub struct Deck {
deck: Vec<Card>,
Expand Down Expand Up @@ -204,8 +206,12 @@ impl Deck {
Deck { deck, it: 0 }
}

// gets a hand from the deck. TODO: return None if the deck is finisced.
/// gets a hand from the deck.
///
pub fn hand(&mut self) -> Option<Hand> {
if self.it > 52 {
return None; // deck is finisced!
}
let hand: Hand = Hand {
hand: self.deck[self.it..=(self.it + 4)].try_into().ok()?,
};
Expand Down Expand Up @@ -239,7 +245,7 @@ impl Display for Deck {
2. Straight Flush
Any sequence of five consecutive cards all of the same suit. For instance, a hand with the cards 5, 6, 7, 8, and 9 of diamonds is a straight flush.
3. Four of a Kind (Quads)
3. Four of a Kind (Poker)
A hand containing four cards of the same rank, along with one unrelated card. For example, four Kings and a 3 would constitute "four of a kind."
4. Full House
Expand Down Expand Up @@ -272,19 +278,23 @@ macro_rules! newcard {

#[macro_export]
macro_rules! hand {

($c:expr,$c1:expr,$c2:expr,$c3:expr,$c4:expr) => {
Hand::new([newcard![$c],newcard![$c1],newcard![$c2],newcard![$c3],newcard![$c4]])
Hand::new([
newcard![$c],
newcard![$c1],
newcard![$c2],
newcard![$c3],
newcard![$c4],
])
};
}

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

#[test]
fn test_try_from_valid_card() {

let card = newcard!["Ad"];
assert_eq!(card.val, 14);
assert_eq!(card.suit, Suit::Diamonds);
Expand All @@ -299,8 +309,7 @@ mod tests {

#[test]
fn test_try_from_valid_hand() {

let hand = hand!["Ad","Kd","Qd","Jd","10d"];
let hand = hand!["Ad", "Kd", "Qd", "Jd", "10d"];
assert_eq!(hand.hand[0], Card::new(14, Suit::Diamonds));
}
}
}
1 change: 0 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,3 @@ pub mod hash_tables;

pub mod fast_evaluator;
pub mod match_evaluator;

21 changes: 18 additions & 3 deletions src/match_evaluator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ impl MatchHandEvaluator {
{
Rank::RoyalFlush
}
[Card { val : v1, .. }, Card { val: v2, .. }, Card { val: v3, .. }, Card { val: v4, .. }, Card { val: v5, .. }]
if (v1 == v2 && v2 == v3 && v3 == v4 || v2 == v3 && v3 == v4 && v4 == v5) =>
{
Rank::FourOfAKind
}
[Card { suit: s1, .. }, Card { suit: s2, .. }, Card { suit: s3, .. }, Card { suit: s4, .. }, Card { suit: s5, .. }]
if Self::suits(s1, s2, s3, s4, s5) =>
{
Expand All @@ -40,6 +45,7 @@ impl MatchHandEvaluator {
}
}

#[macro_export]
macro_rules! assert_rank {
($hand:expr, $rank:expr) => {
assert_eq!(MatchHandEvaluator::slow_eval(&mut $hand), $rank);
Expand All @@ -49,12 +55,21 @@ macro_rules! assert_rank {
#[cfg(test)]
mod test {
use super::MatchHandEvaluator;
use crate::card::{Card, Hand, Rank, Suit, self};
use crate::newcard;
use crate::card::{Card, Hand, Rank};
use crate::hand;
use crate::newcard;

#[test]
fn rank_royal_flush() {
assert_rank!(hand!["Ad","Kd","Qd","Jd","10d"], Rank::RoyalFlush);
assert_rank!(hand!["Ad", "Kd", "Qd", "Jd", "10d"], Rank::RoyalFlush);
assert_rank!(hand!["Ah", "Kh", "Qh", "Jh", "10h"], Rank::RoyalFlush);
assert_rank!(hand!["Ac", "Kc", "Qc", "Jc", "10c"], Rank::RoyalFlush);
assert_rank!(hand!["As", "Ks", "Qs", "Js", "10s"], Rank::RoyalFlush);
}

#[test]
fn rank_four_of_a_kind() {
assert_rank!(hand!["Kd", "Kh", "Kc", "Ks", "Qd"], Rank::FourOfAKind);
assert_rank!(hand!["Kd", "6h", "6c", "6s", "6d"], Rank::FourOfAKind);
}
}

0 comments on commit a1d96d7

Please sign in to comment.