extern crate rand;
use rand::Rng;
use std;
use std::vec::Drain;
#[derive(Debug, Clone, PartialEq)]
pub struct Deck<C> {
draw_pile: Vec<C>,
discard_pile: Vec<C>,
shuffle_discards: bool,
stop_on_discards: bool,
chainer: Vec<C>, }
pub struct DeckBuilder<C> {
draw_pile: Option<Vec<C>>,
discard_pile: Option<Vec<C>>,
shuffle_discards: bool,
stop_on_discards: bool,
pre_shuffle: bool,
}
impl<C> DeckBuilder<C> {
pub fn new() -> Self {
DeckBuilder {
draw_pile: None,
discard_pile: None,
pre_shuffle: true,
shuffle_discards: true,
stop_on_discards: false,
}
}
pub fn draw_pile(mut self, v: Vec<C>) -> Self {
self.draw_pile = Some(v);
self
}
pub fn discard_pile(mut self, v: Vec<C>) -> Self {
self.discard_pile = Some(v);
self
}
pub fn pre_shuffle(mut self, b: bool) -> Self {
self.pre_shuffle = b;
self
}
pub fn shuffle_discards(mut self, b: bool) -> Self {
self.shuffle_discards = b;
self
}
pub fn stop_on_discards(mut self, b: bool) -> Self {
self.stop_on_discards = b;
self
}
pub fn done(mut self) -> Deck<C> {
if self.pre_shuffle {
if let Some(ref mut v) = self.draw_pile {
rand::thread_rng().shuffle(v);
}
if let Some(ref mut v) = self.discard_pile {
rand::thread_rng().shuffle(v);
}
}
Deck {
draw_pile: self.draw_pile.unwrap_or(Vec::new()),
discard_pile: self.discard_pile.unwrap_or(Vec::new()),
shuffle_discards: self.shuffle_discards,
stop_on_discards: self.stop_on_discards,
chainer: Vec::new(),
}
}
}
impl<C> Deck<C> {
pub fn new(v: Vec<C>) -> Self {
Self::build().draw_pile(v).done()
}
pub fn build() -> DeckBuilder<C> {
DeckBuilder::new()
}
pub fn put_discard(&mut self, card: C) {
self.discard_pile.push(card);
}
pub fn discards_to_bottom(&mut self) {
if self.shuffle_discards {
rand::thread_rng().shuffle(&mut self.discard_pile);
}
self.draw_pile.append(&mut self.discard_pile);
}
pub fn shuffle_draw_pile(&mut self) {
rand::thread_rng().shuffle(&mut self.draw_pile);
}
pub fn draw_1(&mut self) -> Option<C> {
return self.draw(1).next();
}
pub fn draw(&mut self, n: usize) -> Drain<C> {
if n <= self.draw_pile.len() {
return self.draw_pile.drain(0..n);
}
if self.stop_on_discards {
return self.draw_pile.drain(0..n);
}
self.discards_to_bottom();
if n <= self.draw_pile.len() {
return self.draw_pile.drain(0..n);
}
self.draw_pile.drain(0..)
}
pub fn draw_all(&mut self) -> Drain<C> {
if !self.stop_on_discards {
self.discards_to_bottom();
}
self.draw_pile.drain(0..)
}
pub fn len(&self) -> usize {
match self.stop_on_discards {
true => self.draw_pile.len(),
false => self.draw_pile.len() + self.discard_pile.len(),
}
}
pub fn draw_len(&self) -> usize {
self.draw_pile.len()
}
pub fn discard_len(&self) -> usize {
self.discard_pile.len()
}
pub fn push_bottom(&mut self, c: C) {
self.draw_pile.push(c);
}
pub fn push_top(&mut self, c: C) {
self.discard_pile.insert(0, c);
}
pub fn push_discards<I: IntoIterator<Item = C>>(&mut self, i: I) {
for c in i {
self.discard_pile.push(c);
}
}
pub fn push_discards_top<I: IntoIterator<Item = C>>(&mut self, i: I) {
for c in i {
self.discard_pile.insert(0, c);
}
}
pub fn dig_for<F>(&mut self, mut f: F) -> Option<C>
where
F: FnMut(&C) -> bool,
{
for i in 0..self.draw_pile.len() {
if f(&self.draw_pile[i]) {
return Some(self.draw_pile.remove(i));
}
}
None
}
pub fn dig_all<F>(&mut self, mut f: F) -> std::vec::IntoIter<C>
where
F: FnMut(&C) -> bool,
{
let mut i = 0;
let mut r_vec = Vec::new();
while i < self.draw_pile.len() {
if f(&self.draw_pile[i]) {
r_vec.push(self.draw_pile.remove(i));
} else {
i += 1;
}
}
r_vec.into_iter()
}
}
impl<'a, C> IntoIterator for &'a Deck<C> {
type Item = &'a C;
type IntoIter = std::iter::Chain<std::slice::Iter<'a, C>, std::slice::Iter<'a, C>>;
fn into_iter(self) -> Self::IntoIter {
match self.stop_on_discards {
true => (self.draw_pile).iter().chain(self.chainer.iter()),
false => (self.draw_pile).iter().chain(self.discard_pile.iter()),
}
}
}
impl<'a, C> IntoIterator for &'a mut Deck<C> {
type Item = &'a mut C;
type IntoIter = std::iter::Chain<std::slice::IterMut<'a, C>, std::slice::IterMut<'a, C>>;
fn into_iter(self) -> Self::IntoIter {
match self.stop_on_discards {
true => (self.draw_pile).iter_mut().chain(self.chainer.iter_mut()),
false => (self.draw_pile)
.iter_mut()
.chain(self.discard_pile.iter_mut()),
}
}
}