*: small refactors and test changes
This commit is contained in:
@@ -17,7 +17,7 @@ impl Iterator for CardIterator {
|
|||||||
suit: Suit::Spade,
|
suit: Suit::Spade,
|
||||||
deck,
|
deck,
|
||||||
}) => {
|
}) => {
|
||||||
self.0 = Card::Joker((deck + 1) * -1);
|
self.0 = Card::Joker(-(deck + 1));
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
Card::PlayingCard(pc) => {
|
Card::PlayingCard(pc) => {
|
||||||
@@ -40,7 +40,7 @@ impl DoubleEndedIterator for CardIterator {
|
|||||||
suit: Suit::Diamond,
|
suit: Suit::Diamond,
|
||||||
deck,
|
deck,
|
||||||
}) => {
|
}) => {
|
||||||
self.0 = Card::Joker((deck + 1) * -1);
|
self.0 = Card::Joker(-(deck + 1));
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
Card::PlayingCard(pc) => {
|
Card::PlayingCard(pc) => {
|
||||||
|
|||||||
@@ -273,11 +273,18 @@ mod test_impls {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rank() {
|
fn rank() {
|
||||||
let ranks = Rank::iter_all().into_iter().collect::<HashSet<_>>();
|
let ranks = Rank::all().into_iter().collect::<HashSet<_>>();
|
||||||
// TEST: Rank::iter_all produces all 13 unique ranks.
|
// TEST: Rank::iter_all produces all 13 unique ranks.
|
||||||
assert_eq!(ranks.len(), 13);
|
assert_eq!(ranks.len(), 13);
|
||||||
|
|
||||||
for rank in Rank::iter_all() {
|
for (ind, rank) in Rank::all().iter().enumerate() {
|
||||||
|
let rest = rank.iter_rest().collect::<HashSet<_>>();
|
||||||
|
// TEST: Rank::iter_rest should generate the remaining ranks after
|
||||||
|
// the current rank in order.
|
||||||
|
assert_eq!(rest.len(), 13 - ind - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for rank in Rank::all() {
|
||||||
let cards = rank.cards().into_iter().collect::<HashSet<_>>();
|
let cards = rank.cards().into_iter().collect::<HashSet<_>>();
|
||||||
assert_eq!(cards.len(), 4, "Expected 4 cards per rank");
|
assert_eq!(cards.len(), 4, "Expected 4 cards per rank");
|
||||||
for c in cards {
|
for c in cards {
|
||||||
@@ -293,8 +300,8 @@ mod test_impls {
|
|||||||
|
|
||||||
// Since there are 4 unique cards generated by rank.cards(), and
|
// Since there are 4 unique cards generated by rank.cards(), and
|
||||||
// they all have the same deck (0) and rank (rank), they must differ
|
// they all have the same deck (0) and rank (rank), they must differ
|
||||||
// by Suit by virtue of ord. 4 suits suggests (by pigeonhole
|
// by Suit. 4 suits suggests (by pigeonhole principle) that all
|
||||||
// principle) that all suits must have been used.
|
// suits must have been used.
|
||||||
|
|
||||||
// So rank.cards() generates all cards of deck 0 that have that rank
|
// So rank.cards() generates all cards of deck 0 that have that rank
|
||||||
// (which is precisely 4 cards). QED.
|
// (which is precisely 4 cards). QED.
|
||||||
@@ -408,7 +415,7 @@ mod test_impls {
|
|||||||
counter
|
counter
|
||||||
};
|
};
|
||||||
|
|
||||||
for (rank, suit) in Rank::iter_all()
|
for (rank, suit) in Rank::all()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.zip_cartesian(Suit::iter_all().into_iter())
|
.zip_cartesian(Suit::iter_all().into_iter())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -113,11 +113,11 @@ mod tests {
|
|||||||
assert_eq!(Pair::new(Card::make_joker(), Card::make_joker()), None);
|
assert_eq!(Pair::new(Card::make_joker(), Card::make_joker()), None);
|
||||||
|
|
||||||
// TEST: Non pair tests.
|
// TEST: Non pair tests.
|
||||||
for (c1, c2) in Rank::iter_all()
|
for (c1, c2) in Rank::all()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
// Generate tuples (r1, r2) where r1 != r2
|
// Generate tuples (r1, r2) where r1 != r2
|
||||||
.flat_map(|r1| {
|
.flat_map(|r1| {
|
||||||
Rank::iter_all()
|
Rank::all()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(move |&r2| r2 != r1)
|
.filter(move |&r2| r2 != r1)
|
||||||
.map(move |r2| (r1, r2))
|
.map(move |r2| (r1, r2))
|
||||||
|
|||||||
@@ -150,18 +150,22 @@ mod tests {
|
|||||||
// Triple::2.
|
// Triple::2.
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
trip.2, card,
|
trip.2, card,
|
||||||
"Expected the highest card of the triple ({}) to be the sole PlayingCard ({card})",
|
"Expected Triple::2 to be the sole PlayingCard"
|
||||||
trip.2
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
trip.high_card(),
|
||||||
|
card,
|
||||||
|
"Expected Triple::HighCard = card"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iterate over all pairs of cards with similar ranks
|
// Iterate over all pairs of cards with similar ranks
|
||||||
for (c1, c2) in Rank::iter_all().into_iter().flat_map(|r| {
|
for (c1, c2) in Rank::all().into_iter().flat_map(|r| {
|
||||||
r.cards().into_iter().zip_cartesian(r.cards().into_iter())
|
r.cards().into_iter().zip_cartesian(r.cards().into_iter())
|
||||||
}) {
|
}) {
|
||||||
let trip = Triple::new(c1, c2, joker);
|
let trip = Triple::new(c1, c2, joker);
|
||||||
// TEST: Any two similar rank cards with 1 joker are a
|
// TEST: Any two similar rank cards with 1 joker is a Triple.
|
||||||
// Triple.
|
|
||||||
assert_ne!(
|
assert_ne!(
|
||||||
trip, None,
|
trip, None,
|
||||||
"Expected ({c1}, {c2}, Joker) to make a Triple"
|
"Expected ({c1}, {c2}, Joker) to make a Triple"
|
||||||
@@ -190,13 +194,16 @@ mod tests {
|
|||||||
trip.1,
|
trip.1,
|
||||||
trip.2,
|
trip.2,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// TEST: Expect triple high card to be the highest card of c1,c2.
|
||||||
|
assert_eq!(trip.high_card(), c2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iterate over all pairs of cards with differing ranks
|
// Iterate over all pairs of cards with differing ranks
|
||||||
for (c1, c2) in Rank::iter_all()
|
for (c1, c2) in Rank::all()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flat_map(|r1| {
|
.flat_map(|r1| {
|
||||||
Rank::iter_all()
|
Rank::all()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(move |&r2| r2 != r1)
|
.filter(move |&r2| r2 != r1)
|
||||||
.map(move |r2| (r1, r2))
|
.map(move |r2| (r1, r2))
|
||||||
@@ -246,6 +253,10 @@ mod tests {
|
|||||||
|
|
||||||
let [c1, c2, c3] = ordered([c1, c2, c3]);
|
let [c1, c2, c3] = ordered([c1, c2, c3]);
|
||||||
|
|
||||||
|
// TEST: Triple::high_card should be c3 (the highest card of the
|
||||||
|
// ordered set).
|
||||||
|
assert_eq!(trip.high_card(), c3);
|
||||||
|
|
||||||
// TEST: If a triple is formed of 3 playing cards, they are
|
// TEST: If a triple is formed of 3 playing cards, they are
|
||||||
// ordered s.t. Triple::2 > Triple::1 > Triple::0.
|
// ordered s.t. Triple::2 > Triple::1 > Triple::0.
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -286,18 +297,11 @@ mod tests {
|
|||||||
let joker = Card::make_joker();
|
let joker = Card::make_joker();
|
||||||
|
|
||||||
for (t1, t2) in
|
for (t1, t2) in
|
||||||
// Iterate through all pairs of differing ranks (r1, r2) where r2 >
|
|
||||||
// r1
|
|
||||||
Rank::iter_all()
|
|
||||||
.into_iter()
|
|
||||||
.flat_map(|r1| {
|
|
||||||
Rank::iter_all()
|
|
||||||
.into_iter()
|
|
||||||
.filter(move |&r2| r2 > r1)
|
|
||||||
.map(move |r2| (r1, r2))
|
|
||||||
})
|
|
||||||
// Generate an exhaustive set of triples where rank(t1) <
|
// Generate an exhaustive set of triples where rank(t1) <
|
||||||
// rank(t2)
|
// rank(t2)
|
||||||
|
Rank::all()
|
||||||
|
.into_iter()
|
||||||
|
.flat_map(move |r1| r1.iter_rest().map(move |r2| (r1, r2)))
|
||||||
.flat_map(|(r1, r2)| {
|
.flat_map(|(r1, r2)| {
|
||||||
exhaustive_triples_rank(r1)
|
exhaustive_triples_rank(r1)
|
||||||
.zip_cartesian(exhaustive_triples_rank(r2))
|
.zip_cartesian(exhaustive_triples_rank(r2))
|
||||||
@@ -310,39 +314,38 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// So high card rank determines ordering between differing ranked
|
// So high card rank determines ordering between differing ranked
|
||||||
// triples.
|
// triples. Let's test what happens within triples of the same high
|
||||||
|
// card rank.
|
||||||
|
|
||||||
// Iterate through all ranks
|
// Iterate through all ranks
|
||||||
for rank in Rank::iter_all() {
|
for rank in Rank::all() {
|
||||||
let cards = rank.cards();
|
let cards = rank.cards();
|
||||||
|
|
||||||
// All possible 2 joker triples for this rank.
|
|
||||||
let two_joker_triples = cards
|
|
||||||
.map(|c| Triple::new(c, joker, joker))
|
|
||||||
.map(Option::unwrap);
|
|
||||||
|
|
||||||
for triple in
|
|
||||||
exhaustive_triples_rank(rank).filter(|x| x.count_jokers() < 2)
|
|
||||||
{
|
|
||||||
for two_joker_trip in two_joker_triples {
|
|
||||||
// TEST: A two joker triple is always worse than any triples
|
|
||||||
// in the same rank that have at most 1 joker.
|
|
||||||
assert!(two_joker_trip < triple);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let [diamond, _, _, spade] = cards;
|
let [diamond, _, _, spade] = cards;
|
||||||
|
|
||||||
// NOTE: By new test this should be safe to unwrap.
|
// NOTE: By new test this should be safe to unwrap.
|
||||||
let minima = Triple::new(diamond, joker, joker).unwrap();
|
let minima = Triple::new(diamond, joker, joker).unwrap();
|
||||||
let maxima = Triple::new(spade, spade, spade).unwrap();
|
let maxima = Triple::new(spade, spade, spade).unwrap();
|
||||||
|
|
||||||
|
// All possible 2 joker triples for this rank.
|
||||||
|
let two_joker_triples = cards
|
||||||
|
.map(|c| Triple::new(c, joker, joker))
|
||||||
|
.map(Option::unwrap);
|
||||||
|
|
||||||
for triple in exhaustive_triples_rank(rank) {
|
for triple in exhaustive_triples_rank(rank) {
|
||||||
// TEST: The lowest possible triple in a rank is a diamond + 2
|
// TEST: The lowest possible triple in a rank is a diamond + 2
|
||||||
// jokers
|
// jokers
|
||||||
assert!(minima <= triple);
|
assert!(minima <= triple);
|
||||||
// TEST: The highest possible triple in a rank is 3 spades
|
// TEST: The highest possible triple in a rank is 3 spades
|
||||||
assert!(maxima >= triple);
|
assert!(maxima >= triple);
|
||||||
|
|
||||||
|
if triple.count_jokers() < 2 {
|
||||||
|
for two_joker_trip in two_joker_triples {
|
||||||
|
// TEST: A two joker triple is always worse than any
|
||||||
|
// triples in the same rank that have at most 1 joker.
|
||||||
|
assert!(two_joker_trip < triple);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -350,8 +353,8 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn footstool() {
|
fn footstool() {
|
||||||
let triples = exhaustive_triples_deck().collect::<Vec<_>>();
|
let triples = exhaustive_triples_deck().collect::<Vec<_>>();
|
||||||
for t1 in &triples {
|
for (ind, t1) in triples.iter().enumerate() {
|
||||||
for t2 in &triples {
|
for t2 in &triples[ind..] {
|
||||||
// TEST: Expected footstool condition
|
// TEST: Expected footstool condition
|
||||||
test_footstool(t1, t2);
|
test_footstool(t1, t2);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,18 +19,17 @@ where
|
|||||||
I::Item: Copy,
|
I::Item: Copy,
|
||||||
{
|
{
|
||||||
/// Exhaustive coupling of two iterators.
|
/// Exhaustive coupling of two iterators.
|
||||||
/// For each x in `self`: for each y in `b`: yield (x, y).
|
/// For each x in `self`: for each y in `other`: yield (x, y).
|
||||||
/// b: B must implement `Clone`.
|
fn zip_cartesian<Other>(
|
||||||
fn zip_cartesian<B>(
|
|
||||||
self,
|
self,
|
||||||
b: B,
|
other: Other,
|
||||||
) -> impl Iterator<Item = (Self::Item, B::Item)> + Clone
|
) -> impl Iterator<Item = (Self::Item, Other::Item)> + Clone
|
||||||
where
|
where
|
||||||
B::Item: Copy,
|
Other::Item: Copy,
|
||||||
B: Iterator + Clone,
|
Other: Iterator + Clone,
|
||||||
{
|
{
|
||||||
self.flat_map(move |a_item| {
|
self.flat_map(move |a_item| {
|
||||||
b.clone().map(move |b_item| (a_item, b_item))
|
other.clone().map(move |b_item| (a_item, b_item))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user