card:impls: *::iter_all and *::cards now return arrays
We know the sizes of the results of these functions beforehand. Fitting it into an ESI was a code smell really. Just return the arrays! Of course, now we need to do array::into_iter for iterator use, but this is way better. Excluding Card::iter_all since we can't know the size of it at compile time. PITA that we can't make it an ESI either.
This commit is contained in:
@@ -7,29 +7,40 @@ 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() -> impl ExactSizeIterator<Item = Rank> + Clone {
|
||||
(0i32..13)
|
||||
.map(|n| n as i64)
|
||||
.map(|n| Rank::try_from(n).unwrap())
|
||||
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,
|
||||
]
|
||||
}
|
||||
|
||||
/// 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) -> impl ExactSizeIterator<Item = Card> + Clone {
|
||||
let n = self as i32;
|
||||
((n * 4)..((n + 1) * 4)).map(|x| Card::from(x as i64))
|
||||
pub fn cards(self) -> [Card; 4] {
|
||||
Suit::iter_all().map(move |suit| Card::make_playing_card(0, self, suit))
|
||||
}
|
||||
}
|
||||
|
||||
impl Suit {
|
||||
/// Generate an iterator over all suits.
|
||||
pub fn iter_all() -> impl ExactSizeIterator<Item = Suit> + Clone {
|
||||
(0i32..4).map(|n| Suit::try_from(n as i64).unwrap())
|
||||
pub fn iter_all() -> [Suit; 4] {
|
||||
[Suit::Diamond, Suit::Club, Suit::Heart, Suit::Spade]
|
||||
}
|
||||
|
||||
/// Generate an iterator over all cards within a suit, ordered by Rank. The
|
||||
/// cards are all default initialised in terms of deck (0).
|
||||
pub fn cards(self) -> impl ExactSizeIterator<Item = Card> + Clone {
|
||||
pub fn cards(self) -> [Card; 13] {
|
||||
Rank::iter_all().map(move |rank| Card::make_playing_card(0, rank, self))
|
||||
}
|
||||
}
|
||||
@@ -47,11 +58,12 @@ 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) -> impl ExactSizeIterator<Item = Self> + Clone {
|
||||
(0i32..52)
|
||||
.map(|x| x as i64)
|
||||
.map(move |x| x + (52 * n))
|
||||
.map(|x| PlayingCard::try_from(x).unwrap())
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -268,18 +268,17 @@ mod test_impls {
|
||||
|
||||
use crate::{
|
||||
card::{Card, PlayingCard, Rank, Suit},
|
||||
exactsizearr::ExactSizedArr,
|
||||
zipcartesian::ZipCartesianExt,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn rank() {
|
||||
let ranks = Rank::iter_all().collect::<HashSet<_>>();
|
||||
let ranks = Rank::iter_all().into_iter().collect::<HashSet<_>>();
|
||||
// TEST: Rank::iter_all produces all 13 unique ranks.
|
||||
assert_eq!(ranks.len(), 13);
|
||||
|
||||
for rank in Rank::iter_all() {
|
||||
let cards = rank.cards().collect::<HashSet<_>>();
|
||||
let cards = rank.cards().into_iter().collect::<HashSet<_>>();
|
||||
assert_eq!(cards.len(), 4, "Expected 4 cards per rank");
|
||||
for c in cards {
|
||||
// TEST: rank.cards() generates Playing Cards of the same rank
|
||||
@@ -304,12 +303,12 @@ mod test_impls {
|
||||
|
||||
#[test]
|
||||
fn suit() {
|
||||
let suits = Suit::iter_all().collect::<HashSet<_>>();
|
||||
let suits = Suit::iter_all().into_iter().collect::<HashSet<_>>();
|
||||
// TEST: Suit::iter_all produces all 4 unique suits.
|
||||
assert_eq!(suits.len(), 4);
|
||||
|
||||
for suit in Suit::iter_all() {
|
||||
let cards = suit.cards().collect::<HashSet<_>>();
|
||||
let cards = suit.cards().into_iter().collect::<HashSet<_>>();
|
||||
assert_eq!(cards.len(), 13, "Expected 13 cards per suit");
|
||||
|
||||
for c in cards {
|
||||
@@ -331,8 +330,9 @@ mod test_impls {
|
||||
#[test]
|
||||
fn playing_card() {
|
||||
for deck in 0..10 {
|
||||
let playing_cards =
|
||||
PlayingCard::iter_all(deck).collect::<HashSet<_>>();
|
||||
let playing_cards = PlayingCard::iter_all(deck)
|
||||
.into_iter()
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
// TEST: Expected 52 cards to be generated by PlayingCard::iter_all.
|
||||
assert_eq!(
|
||||
@@ -341,13 +341,7 @@ mod test_impls {
|
||||
"Expected 52 cards in a playing card deck"
|
||||
);
|
||||
|
||||
for card in PlayingCard::iter_all(deck)
|
||||
.into_array::<52>()
|
||||
.unwrap_or_else(|_| {
|
||||
unreachable!(
|
||||
"Look at previous assertion; there must be 52 cards in the iterator."
|
||||
)
|
||||
}) {
|
||||
for card in PlayingCard::iter_all(deck) {
|
||||
// TEST: card.deck must match the input deck
|
||||
assert_eq!(card.deck, deck);
|
||||
let numeral = i64::from(card);
|
||||
@@ -414,7 +408,9 @@ mod test_impls {
|
||||
counter
|
||||
};
|
||||
|
||||
for (rank, suit) in Rank::iter_all().zip_cartesian(Suit::iter_all())
|
||||
for (rank, suit) in Rank::iter_all()
|
||||
.into_iter()
|
||||
.zip_cartesian(Suit::iter_all().into_iter())
|
||||
{
|
||||
// TEST: We expect `decks` instances of a (rank, suit)
|
||||
// combination in Card::iter_all(decks).
|
||||
|
||||
@@ -108,14 +108,18 @@ mod tests {
|
||||
|
||||
// TEST: Non pair tests.
|
||||
for (c1, c2) in Rank::iter_all()
|
||||
.into_iter()
|
||||
// Generate tuples (r1, r2) where r1 != r2
|
||||
.flat_map(|r1| {
|
||||
Rank::iter_all()
|
||||
.into_iter()
|
||||
.filter(move |&r2| r2 != r1)
|
||||
.map(move |r2| (r1, r2))
|
||||
})
|
||||
// Generate all cards where their ranks differ
|
||||
.flat_map(|(r1, r2)| r1.cards().zip_cartesian(r2.cards()))
|
||||
.flat_map(|(r1, r2)| {
|
||||
r1.cards().into_iter().zip_cartesian(r2.cards().into_iter())
|
||||
})
|
||||
{
|
||||
// TEST: Two cards of differing rank cannot be a pair
|
||||
let pair = Pair::new(c1, c2);
|
||||
@@ -150,6 +154,7 @@ mod tests {
|
||||
;
|
||||
PlayingCard::iter_all(0)
|
||||
.map(Card::PlayingCard)
|
||||
.into_iter()
|
||||
// Flat Map every Playing Card (c1) into combinations (Card of same
|
||||
// rank as c1, c1)
|
||||
.flat_map(|c1| c1.rank().unwrap().cards().map(move |c2| (c1, c2)))
|
||||
|
||||
@@ -151,9 +151,9 @@ mod tests {
|
||||
}
|
||||
|
||||
// Iterate over all pairs of cards with similar ranks
|
||||
for (c1, c2) in
|
||||
Rank::iter_all().flat_map(|r| r.cards().zip_cartesian(r.cards()))
|
||||
{
|
||||
for (c1, c2) in Rank::iter_all().into_iter().flat_map(|r| {
|
||||
r.cards().into_iter().zip_cartesian(r.cards().into_iter())
|
||||
}) {
|
||||
let trip = Triple::new(c1, c2, joker);
|
||||
// TEST: Any two similar rank cards with 1 joker are a
|
||||
// Triple.
|
||||
@@ -189,12 +189,16 @@ mod tests {
|
||||
|
||||
// Iterate over all pairs of cards with differing ranks
|
||||
for (c1, c2) in Rank::iter_all()
|
||||
.into_iter()
|
||||
.flat_map(|r1| {
|
||||
Rank::iter_all()
|
||||
.into_iter()
|
||||
.filter(move |&r2| r2 != r1)
|
||||
.map(move |r2| (r1, r2))
|
||||
})
|
||||
.flat_map(|(r1, r2)| r1.cards().zip_cartesian(r2.cards()))
|
||||
.flat_map(|(r1, r2)| {
|
||||
r1.cards().into_iter().zip_cartesian(r2.cards().into_iter())
|
||||
})
|
||||
{
|
||||
// TEST: Cannot make a triple out of 1 joker and two different rank
|
||||
// cards
|
||||
@@ -206,9 +210,13 @@ mod tests {
|
||||
}
|
||||
|
||||
// Iterate over all triples of cards (regardless of rank)
|
||||
for (c1, (c2, c3)) in PlayingCard::iter_all(0).zip_cartesian(
|
||||
PlayingCard::iter_all(0).zip_cartesian(PlayingCard::iter_all(0)),
|
||||
) {
|
||||
for (c1, (c2, c3)) in
|
||||
PlayingCard::iter_all(0).into_iter().zip_cartesian(
|
||||
PlayingCard::iter_all(0)
|
||||
.into_iter()
|
||||
.zip_cartesian(PlayingCard::iter_all(0).into_iter()),
|
||||
)
|
||||
{
|
||||
let [c1, c2, c3] = [c1, c2, c3].map(Card::PlayingCard);
|
||||
let trip = Triple::new(c1, c2, c3);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user