use std::cmp::min;
use super::{Cards, Pile, PileMut};
use crate::card::Card;
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct Split {
pile: Cards,
left_len: usize,
}
#[derive(Debug, Clone, Copy)]
pub struct Segment<'a>(&'a Split);
#[derive(Debug)]
pub struct SegmentMut<'a>(&'a mut Split);
impl Split {
pub const fn empty() -> Self {
Self {
pile: Cards::empty(),
left_len: 0,
}
}
pub fn from_cards(pile: Cards, left_len: usize) -> Self {
assert!(left_len <= pile.len());
Self { pile, left_len }
}
pub fn from_left(left_pile: Cards) -> Self {
let left_len = left_pile.len();
Self {
pile: left_pile,
left_len,
}
}
pub fn from_right(right_pile: Cards) -> Split {
Self {
pile: right_pile,
left_len: 0,
}
}
pub fn left(&self) -> Segment<'_> {
Segment(self)
}
pub fn right(&self) -> Segment<'_> {
Segment(self)
}
pub fn right_mut(&mut self) -> SegmentMut<'_> {
SegmentMut(self)
}
pub fn cards_split(&self) -> (&[Card], &[Card]) {
self.pile.cards().split_at(self.left_len)
}
pub fn set_left_length(&mut self, len: usize) {
assert!(len <= self.len());
self.left_len = len;
}
pub fn set_right_length(&mut self, len: usize) {
assert!(len <= self.len());
self.left_len = self.len() - len;
}
}
impl IntoIterator for Split {
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.pile.into_iter()
}
}
impl<'a> IntoIterator for &'a Split {
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.pile).into_iter()
}
}
impl<'a> IntoIterator for Segment<'a> {
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.0.into_iter()
}
}
impl<'a> IntoIterator for &'a Segment<'a> {
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.0.into_iter()
}
}
impl<'a> IntoIterator for SegmentMut<'a> {
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.0).into_iter()
}
}
impl<'a> IntoIterator for &'a SegmentMut<'a> {
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.0).into_iter()
}
}
impl Extend<Card> for Split {
fn extend<I>(&mut self, cards: I)
where
I: IntoIterator<Item = Card>,
{
self.place(cards);
}
}
impl<'a> Extend<Card> for SegmentMut<'a> {
fn extend<I>(&mut self, cards: I)
where
I: IntoIterator<Item = Card>,
{
self.place(cards);
}
}
impl Pile for Split {
fn cards(&self) -> &[Card] {
self.pile.cards()
}
fn len(&self) -> usize {
self.pile.len()
}
fn is_empty(&self) -> bool {
self.pile.is_empty()
}
}
impl PileMut for Split {
fn take_at_most(&mut self, count: usize) -> Cards {
let pile = self.pile.take_at_most(count);
self.left_len = min(self.left_len, self.pile.len());
pile
}
fn take_at_most_one(&mut self) -> Option<Card> {
let card = self.pile.take_at_most_one();
self.left_len = min(self.left_len, self.pile.len());
card
}
fn take_or_none(&mut self, count: usize) -> Option<Cards> {
let pile = self.pile.take_or_none(count);
self.left_len = min(self.left_len, self.pile.len());
pile
}
fn take_exactly(&mut self, count: usize) -> Cards {
let pile = self.pile.take_exactly(count);
self.left_len = min(self.left_len, self.pile.len());
pile
}
fn take_exactly_one(&mut self) -> Card {
let card = self.pile.take_exactly_one();
self.left_len = min(self.left_len, self.pile.len());
card
}
fn take_all(&mut self) -> Cards {
self.left_len = 0;
self.pile.take_all()
}
fn place<I>(&mut self, cards: I)
where
I: IntoIterator<Item = Card>,
{
self.pile.place(cards);
}
fn place_one(&mut self, card: Card) {
self.pile.place_one(card);
}
}
impl<'a> Pile for Segment<'a> {
fn cards(&self) -> &[Card] {
&self.0.pile.cards()[0..self.0.left_len]
}
fn len(&self) -> usize {
self.0.left_len
}
fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl<'a> Pile for SegmentMut<'a> {
fn cards(&self) -> &[Card] {
&self.0.pile.cards()[self.0.left_len..]
}
fn len(&self) -> usize {
self.0.len() - self.0.left_len
}
fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl<'a> PileMut for SegmentMut<'a> {
fn take_at_most(&mut self, count: usize) -> Cards {
let capped_count = min(count, self.len());
self.0.pile.take_at_most(capped_count)
}
fn take_at_most_one(&mut self) -> Option<Card> {
(!self.is_empty()).then(|| self.0.pile.take_exactly_one())
}
fn take_or_none(&mut self, count: usize) -> Option<Cards> {
(count <= self.len()).then(|| self.0.pile.take_exactly(count))
}
fn take_exactly(&mut self, count: usize) -> Cards {
assert!(count <= self.len());
self.0.pile.take_exactly(count)
}
fn take_exactly_one(&mut self) -> Card {
assert!(!self.is_empty());
self.0.pile.take_exactly_one()
}
fn take_all(&mut self) -> Cards {
self.0.pile.take_exactly(self.len())
}
fn place<I>(&mut self, cards: I)
where
I: IntoIterator<Item = Card>,
{
self.0.pile.place(cards);
}
fn place_one(&mut self, card: Card) {
self.0.pile.place_one(card);
}
}