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 (ie 5 cards) are consecutive, eg 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 Rank
s were an array or a Vec<Rank>
(can be already sorted). The issue is checking if the Hand
's Rank
s 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 Rank
s contains the sorted array of Hand
's Ranks
.
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).
You can give enum variants values (C-like) and easily compare them that way:
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord)]
enum Rank {
Two=2,
Three,
Four,
Five,
Six,
Seven,
Eight,
Nine,
Ten,
Jack,
Queen,
King,
Ace
}
impl Rank {
// Passing by value as Rank: Copy
pub fn next_is(self, other: Rank) -> bool {
((self as i32) + 1) == (other as i32)
}
}
Then is_straight
is simple to implement using the next_is
method.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.