use std::mem::take;
use super::{Pile, PileMut, Split};
use crate::card::Card;
use crate::enums::EnumSequence as _;
use crate::shuffle::Shuffle;
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct Cards {
cards: Vec<Card>,
}
impl Cards {
pub const fn empty() -> Self {
Self { cards: Vec::new() }
}
pub fn deck() -> Self {
Self {
cards: Card::values_iter().collect(),
}
}
pub fn shuffled_deck<S>(shuffle: S) -> Self
where
S: Shuffle,
{
let cards = Card::values_iter().collect::<Vec<_>>();
let permutation = shuffle.permutation(cards.len());
let cards = permutation.permute(&cards);
Self { cards }
}
pub fn into_split(self, left_len: usize) -> Split {
Split::from_cards(self, left_len)
}
pub fn into_left_split(self) -> Split {
Split::from_left(self)
}
pub fn into_right_split(self) -> Split {
Split::from_right(self)
}
#[must_use]
pub fn flipped(mut self) -> Self {
self.cards.reverse();
self
}
}
impl From<Vec<Card>> for Cards {
fn from(cards: Vec<Card>) -> Self {
Self { cards }
}
}
impl<const N: usize> From<[Card; N]> for Cards {
fn from(cards: [Card; N]) -> Self {
Self {
cards: cards.into(),
}
}
}
impl FromIterator<Card> for Cards {
fn from_iter<I>(cards: I) -> Self
where
I: IntoIterator<Item = Card>,
{
Self {
cards: cards.into_iter().collect(),
}
}
}
impl IntoIterator for Cards {
type Item = Card;
type IntoIter = impl Iterator<Item = Self::Item>
+ DoubleEndedIterator<Item = Self::Item>
+ ExactSizeIterator<Item = Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.cards.into_iter()
}
}
impl<'a> IntoIterator for &'a Cards {
type Item = Card;
type IntoIter = impl Iterator<Item = Self::Item>
+ DoubleEndedIterator<Item = Self::Item>
+ ExactSizeIterator<Item = Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.cards.iter().copied()
}
}
impl Extend<Card> for Cards {
fn extend<I>(&mut self, cards: I)
where
I: IntoIterator<Item = Card>,
{
self.place(cards);
}
}
impl Pile for Cards {
fn cards(&self) -> &[Card] {
&self.cards
}
fn len(&self) -> usize {
self.cards.len()
}
fn is_empty(&self) -> bool {
self.cards.is_empty()
}
}
impl PileMut for Cards {
fn take_at_most(&mut self, count: usize) -> Cards {
let index = self.len().saturating_sub(count);
self.cards.split_off(index).into()
}
fn take_at_most_one(&mut self) -> Option<Card> {
self.cards.pop()
}
fn take_or_none(&mut self, count: usize) -> Option<Cards> {
self.len()
.checked_sub(count)
.map(|index| self.cards.split_off(index).into())
}
fn take_exactly(&mut self, count: usize) -> Cards {
assert!(count <= self.len());
let index = self.len() - count;
self.cards.split_off(index).into()
}
fn take_exactly_one(&mut self) -> Card {
assert!(!self.is_empty());
self.take_at_most_one().unwrap()
}
fn take_all(&mut self) -> Cards {
take(self)
}
fn place<I>(&mut self, cards: I)
where
I: IntoIterator<Item = Card>,
{
self.cards.extend(cards);
}
fn place_one(&mut self, card: Card) {
self.cards.push(card);
}
}