card:impls:rank: new iter_rest function
This commit is contained in:
@@ -7,41 +7,34 @@ ExactSizeIterator => Map<Range<i64>> is not an ESI. But Range<i32> is an ESI.
|
||||
|
||||
impl Rank {
|
||||
/// Generate an iterator over all ranks.
|
||||
pub fn iter_all() -> [Rank; 13] {
|
||||
[
|
||||
Rank::Three,
|
||||
Rank::Four,
|
||||
Rank::Five,
|
||||
Rank::Six,
|
||||
Rank::Seven,
|
||||
Rank::Eight,
|
||||
Rank::Nine,
|
||||
Rank::Ten,
|
||||
Rank::Jack,
|
||||
Rank::Queen,
|
||||
Rank::King,
|
||||
Rank::Ace,
|
||||
Rank::Two,
|
||||
]
|
||||
pub fn all() -> [Rank; 13] {
|
||||
std::array::from_fn(|i| Rank::try_from(i as i64).unwrap())
|
||||
}
|
||||
|
||||
/// Generate an iterator over all ranks after the current one.
|
||||
pub fn iter_rest(self) -> impl ExactSizeIterator<Item = Rank> + Clone {
|
||||
(((self as i32) + 1)..13).map(|x| Rank::try_from(x as i64).unwrap())
|
||||
}
|
||||
|
||||
/// Generate an iterator over all cards within a rank, ordered by Suit. The
|
||||
/// cards are all default initialised w.r.t. deck (0).
|
||||
pub fn cards(self) -> [Card; 4] {
|
||||
Suit::iter_all().map(move |suit| Card::make_playing_card(0, self, suit))
|
||||
let n = self as usize;
|
||||
std::array::from_fn(|x| Card::from((x + (n * 4)) as i64))
|
||||
}
|
||||
}
|
||||
|
||||
impl Suit {
|
||||
/// Generate an iterator over all suits.
|
||||
pub fn iter_all() -> [Suit; 4] {
|
||||
[Suit::Diamond, Suit::Club, Suit::Heart, Suit::Spade]
|
||||
std::array::from_fn(|i| Suit::try_from(i as i64).unwrap())
|
||||
}
|
||||
|
||||
/// Generate an iterator over all cards within a suit, ordered by Rank. The
|
||||
/// cards are all default initialised in terms of deck (0).
|
||||
/// cards are all default initialised w.r.t. deck (0).
|
||||
pub fn cards(self) -> [Card; 13] {
|
||||
Rank::iter_all().map(move |rank| Card::make_playing_card(0, rank, self))
|
||||
let n = self as usize;
|
||||
std::array::from_fn(|x| Card::from((n + (x * 4)) as i64))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +43,12 @@ impl PlayingCard {
|
||||
Self { deck, rank, suit }
|
||||
}
|
||||
|
||||
/// Return the index of this playing card in [0, 52), ignoring the deck it
|
||||
/// belongs to.
|
||||
///
|
||||
/// This means any two playing cards from different decks may be equivalent
|
||||
/// under PlayingCard::abs if their ranks and suits match, which is used in
|
||||
/// the Ordering implementation [[file:ord.rs::impl Ord for PlayingCard {]].
|
||||
pub fn abs(&self) -> i64 {
|
||||
let rank = self.rank as i64;
|
||||
let suit = self.suit as i64;
|
||||
@@ -59,11 +58,10 @@ impl PlayingCard {
|
||||
/// Generate an iterator over all Playing Cards in the `nth` deck. By
|
||||
/// construction this is in ascending order.
|
||||
pub fn iter_all(n: i64) -> [PlayingCard; 52] {
|
||||
let mut cards: [PlayingCard; 52] = [PlayingCard::default(); 52];
|
||||
for i in 0..52 {
|
||||
cards[i] = PlayingCard::try_from((i as i64) + (52 * n)).unwrap();
|
||||
}
|
||||
cards
|
||||
assert!(n >= 0 && (n * 53) < i64::MAX);
|
||||
std::array::from_fn(|x| {
|
||||
PlayingCard::try_from((x as i64) + (n * 52)).unwrap()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,12 +85,16 @@ impl Card {
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the rank of the current Card. Returns None iff the current Card
|
||||
/// is a Joker.
|
||||
pub fn rank(&self) -> Option<Rank> {
|
||||
self.playing_card().and_then(|pc| Some(pc.rank))
|
||||
self.playing_card().map(|pc| pc.rank)
|
||||
}
|
||||
|
||||
/// Return the suit of the current Card. Returns None iff the current Card
|
||||
/// is a Joker.
|
||||
pub fn suit(&self) -> Option<Suit> {
|
||||
self.playing_card().and_then(|pc| Some(pc.suit))
|
||||
self.playing_card().map(|pc| pc.suit)
|
||||
}
|
||||
|
||||
pub fn deck_abs(&self) -> i64 {
|
||||
@@ -102,15 +104,21 @@ impl Card {
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate an iterator over `n` decks of Cards. Each deck is concatenated
|
||||
/// together. By construction, each "deck" of the iterator is in ascending
|
||||
/// order.
|
||||
/// Generate an iterator over `n` decks of Cards. By construction, the
|
||||
/// iterator is ordered.
|
||||
///
|
||||
/// Note that each deck gets two jokers.
|
||||
/// Note that each deck gets two jokers, so there are 2`n` jokers total.
|
||||
pub fn iter_all(n: i64) -> impl Iterator<Item = Card> + Clone {
|
||||
// NOTE: I cannot make this into an ExactSizeIterator using the i32
|
||||
// trick. Chain<ESI, ESI> is not an ESI, nor is FlatMap<T,U,T->U>
|
||||
// (where T and U are ESIs).
|
||||
// We can't know the compile time size of this because we're taking the
|
||||
// number of decks at runtime. So no arrays here.
|
||||
|
||||
// We know the size of this iterator beforehand: it's 54 * n. Because
|
||||
// of https://github.com/rust-lang/rust/pull/22299, Range<i64> is not an
|
||||
// ExactSizeIterator => Map<Range<i64>> is not an ESI. Range<i32> is an
|
||||
// ESI, but we can't safely make the range [-2n, 52n] into a Range<i32>
|
||||
// because of n being i64. So we have to leave this as a generic
|
||||
// iterator.
|
||||
|
||||
(-(n * 2)..(52 * n)).map(Card::from)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user