Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Checking for consecutiveness of values in Rust

Tags:

rust

I am currently implementing a poker game and I have encountered an issue that sounds really simple; it may be so, but I can't think of an idiomatic solution: how do I check if a hand is a straight?

A straight is when all the ranks of the cards in a hand (i.e. 5 cards) are consecutive, e.g. Two, Three, Four, Five, Six. The suit can be disregarded (otherwise this would be a check for a straight flush).

Consider the following code:

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

#[derive(Clone, Copy, PartialEq)]
enum Suit {
    Spades,
    Clubs,
    Diamonds,
    Hearts
}

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

struct Hand(Vec<Card>);

impl Hand {
    fn is_straight(&self) -> bool {
        // this should be easy
    }
}

The point is not iterating over an enum - I know this currently can't be done in Rust. I am not sure how to implement this if Ranks were an array or a Vec<Rank> (can be already sorted). The issue is checking if the Hand's Ranks are consecutive (like succ or pred in Haskell).

Any ideas how to do it idiomatically in vanilla Rust? The best I have come up with is checking if a sorted array of all Ranks contains the sorted array of Hand's Ranks.

like image 856
ljedrz Avatar asked Sep 13 '25 04:09

ljedrz


1 Answers

As Chris Emerson already said, you can assign integer values to enum variants and then cast it via the as operator. So we have:

#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord)]
enum Rank {
    Two = 2,
    Three,
    Four,
    // ...
}

The method is_straight() can be implemented using iterator magic:

fn is_straight(&self) -> bool {
    self.0
        .iter()
        .map(|c| c.rank as i8 - self.0[0].rank as i8)
        .eq(0..5)
}

The unchecked indexing self.0[0] is safe, because the closure in map() is only called when at least one element is within the vector. And it seems to work (I removed the Suit to reduce noise).

like image 89
Lukas Kalbertodt Avatar answered Sep 15 '25 22:09

Lukas Kalbertodt