1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
extern crate rand;

use std;
use std::vec::{Drain};
use rand::Rng;

///A Deck of cards
#[derive(Debug,Clone)]
pub struct Deck<C>{
    draw_pile:Vec<C>,
    discard_pile:Vec<C>,
    shuffle_discards:bool,
    stop_on_discards:bool,
    chainer:Vec<C>,//Enables Chain to return something in IntoIter, 
}

/// A builder for a deck of cards. use "done" to finish.
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,
        }
    }
    ///Fill the Draw Pile with the supplied vector, consuming it
    pub fn draw_pile(mut self,v:Vec<C>)->Self{
        self.draw_pile = Some(v);
        self
    }

    ///fill the Discard pile with the supplied vector consuming it
    pub fn discard_pile(mut self,v:Vec<C>)->Self{
        self.discard_pile = Some(v);
        self
    }

    /// Shuffle all cards, at constrution? 
    /// default: true
    pub fn pre_shuffle(mut self,b:bool)->Self{
        self.pre_shuffle = b;
        self
    }

    /// Shuffle discards before adding to the bottom of the draw_pile?
    /// default: true
    pub fn shuffle_discards(mut self,b:bool)->Self{
        self.shuffle_discards = b;
        self
    }
    
    /// If true, the deck is considered ending at the bottom of the draw pile.
    /// This is for all iterators and len
    /// Default: false
    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>{
    ///Builds a deck using the supplied cards and defaults for all other options
    pub fn new(v:Vec<C>)->Self{
        Self::build().draw_pile(v).done()
    }

    ///Creates a Builder for the Deck, see DeckBuilder
    pub fn build()->DeckBuilder<C>{
        DeckBuilder::new()
    }


    ///Add a card to the discard pile
    pub fn put_discard(&mut self,card:C){
        self.discard_pile.push(card);
    }

    /// Adds the Discard Pile to the bottom of the draw pile, shuffling if shuffle_discards
    /// ```
    /// use card_deck::Deck;
    /// let mut dk = Deck::build()
    ///             .draw_pile(vec![1,2,3])
    ///             .discard_pile(vec![4])
    ///             .stop_on_discards(true).done();
    ///
    /// assert_eq!(dk.len(),3);
    /// assert_eq!(dk.discard_len(),1);
    /// dk.discards_to_bottom();
    /// assert_eq!(dk.len(),4);
    /// assert_eq!(dk.discard_len(),0);
    ///
    /// assert_eq!(dk.draw_all().last(),Some(4));
    ///
    /// ```
    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);
    //    self.discard_pile = Vec::new();
    }

    pub fn shuffle_draw_pile(&mut self){
        rand::thread_rng().shuffle(&mut self.draw_pile);
    }

    ///Returns None if nothing to draw 
    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..)
    }

    ///returns the maximum number of cards that can be drawn in a single draw
    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(&mut self,c:C){
        self.discard_pile.push(c);
    }
  
    pub fn push_discards_top(&mut self,c:C){
        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
    }

    ///Currently slow, as for each found element has to do slow remove,
    ///When drain_filter is off nightly will be fixed to use that.
    ///Dont rely on this returning an IntoIter, but expect an Iterator of some form
    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()
    }
}


/// Peeking cards
/// ```
/// use card_deck::Deck;
/// let dk = Deck::build().draw_pile(vec![1,2,3]).discard_pile(vec![4]).done();
/// let mut n = 0;
/// for c in &dk{
///     n += c;
/// }
/// assert_eq!(n,10);
///
/// //with stop_on_discards
///
/// let dk = Deck::build().draw_pile(vec![1,2,3]).discard_pile(vec![4])
///                 .stop_on_discards(true).done();
/// let mut n = 0;
/// for c in &dk{
///     n += c;
/// }
/// assert_eq!(n,6);
/// 
/// ```
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()),
        }
    }
}


/// Tweaking cards
/// ```
/// use card_deck::Deck;
/// let mut dk = Deck::build().draw_pile(vec![1,2,3]).pre_shuffle(false).done();
/// {
///     for c in &mut dk{
///       *c = *c +1;
///     }
/// }
///
/// assert_eq!(dk.draw_1(),Some(2));
/// ```
///
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()),
        }
    }
}