random_wheel/random_wheel.rs
1extern crate rand;
2use std::iter::repeat;
3use std::collections::VecDeque;
4use std::collections::vec_deque::{ IntoIter, Iter, IterMut };
5use self::rand::Rng;
6
7/// a little implementation of a random-wheel.
8pub struct RandomWheel<T> {
9 /// the sum of all probabilities in this wheel.
10 proba_sum: f32,
11 /// all the (probability, data) in a linked-list to pop easily.
12 cards: VecDeque<(f32, T)>
13}
14
15impl<T: Clone> Clone for RandomWheel<T> {
16 fn clone(&self) -> RandomWheel<T> {
17 RandomWheel{
18 proba_sum: self.proba_sum,
19 cards: self.cards.clone()
20 }
21 }
22}
23
24impl<T> IntoIterator for RandomWheel<T> {
25
26 type Item = (f32, T);
27 type IntoIter = IntoIter<(f32, T)>;
28
29 /// Creates a consuming iterator, that is, one that moves each value out of
30 /// the randomWheel (from start to end).
31 #[inline]
32 fn into_iter(self) -> IntoIter<(f32, T)> {
33 self.cards.into_iter()
34 }
35}
36
37impl<T> RandomWheel<T> {
38 /// create a new random-wheel from vector.
39 /// # Example
40 ///
41 /// ```
42 /// use random_wheel::RandomWheel;
43 ///
44 /// let numbers: Vec<_> = (0..20).collect();
45 ///
46 /// // default probability is set to 1.0 for each element
47 /// let rw: RandomWheel<u8> = RandomWheel::from_vec(numbers);
48 /// ```
49 pub fn from_vec(vector: Vec<T>) -> RandomWheel<T> {
50
51 RandomWheel {
52
53 proba_sum: vector.len() as f32,
54 cards: repeat(1.0).into_iter().zip(vector).collect()
55 }
56 }
57
58 /// create a new empty random-wheel.
59 /// # Example
60 ///
61 /// ```
62 /// use random_wheel::RandomWheel;
63 ///
64 /// let rw: RandomWheel<u8> = RandomWheel::new();
65 /// ```
66 pub fn new() -> RandomWheel<T> {
67
68 RandomWheel {
69
70 proba_sum: 0.,
71 cards: VecDeque::new()
72 }
73 }
74
75 /// Creates an empty RandomWheel with space for at least n elements.
76 /// # Example
77 ///
78 /// ```
79 /// use random_wheel::RandomWheel;
80 ///
81 /// let numbers: Vec<_> = (0..20).collect();
82 /// let mut rw: RandomWheel<u8> = RandomWheel::with_capacity(numbers.len());
83 ///
84 /// assert_eq!(rw.len(), 0);
85 /// ```
86 pub fn with_capacity(n: usize) -> RandomWheel<T> {
87
88 RandomWheel {
89
90 proba_sum: 0.,
91 cards: VecDeque::with_capacity(n)
92 }
93 }
94
95 /// Reserves capacity for at least `additional` more elements to be inserted
96 /// in the given `Ringbuf`.
97 /// The collection may reserve more space to avoid frequent reallocations.
98 /// # Example
99 ///
100 /// ```
101 /// use random_wheel::RandomWheel;
102 ///
103 /// let mut rw: RandomWheel<u8> = RandomWheel::new();
104 /// rw.reserve(20);
105 ///
106 /// assert_eq!(rw.len(), 0);
107 /// ```
108 pub fn reserve(&mut self, additional: usize) {
109 self.cards.reserve(additional);
110 }
111
112 /// Returns the number of elements the RandomWheel can hold without
113 /// reallocating.
114 /// # Example
115 ///
116 /// ```
117 /// use random_wheel::RandomWheel;
118 ///
119 /// let rw: RandomWheel<u8> = RandomWheel::new();
120 ///
121 /// println!("actual capacity: {}", rw.capacity());
122 /// ```
123 pub fn capacity(&self) -> usize {
124 self.cards.capacity()
125 }
126
127 /// returns the number of elements in the wheel.
128 /// # Example
129 ///
130 /// ```
131 /// use random_wheel::RandomWheel;
132 ///
133 /// let mut rw = RandomWheel::new();
134 ///
135 /// assert_eq!(rw.len(), 0);
136 ///
137 /// rw.push(1., 'r');
138 /// rw.push(1., 'c');
139 /// rw.push(1., 'a');
140 ///
141 /// assert_eq!(rw.len(), 3);
142 /// ```
143 pub fn len(&self) -> usize {
144 self.cards.len()
145 }
146
147 /// remove all elements in this wheel.
148 /// # Example
149 ///
150 /// ```
151 /// use random_wheel::RandomWheel;
152 ///
153 /// let mut rw = RandomWheel::new();
154 ///
155 /// rw.push(1., 'r');
156 /// rw.push(1., 'c');
157 /// rw.push(1., 'a');
158 ///
159 /// assert_eq!(rw.len(), 3);
160 ///
161 /// rw.clear();
162 ///
163 /// assert_eq!(rw.len(), 0);
164 /// ```
165 pub fn clear(&mut self) {
166 self.cards.clear()
167 }
168
169 /// returns `true` if this wheel is empty else return `false`.
170 /// # Example
171 ///
172 /// ```
173 /// use random_wheel::RandomWheel;
174 ///
175 /// let mut rw = RandomWheel::new();
176 ///
177 /// assert_eq!(rw.is_empty(), true);
178 ///
179 /// rw.push(1., 'r');
180 /// rw.push(1., 'c');
181 /// rw.push(1., 'a');
182 ///
183 /// assert_eq!(rw.is_empty(), false);
184 /// ```
185 pub fn is_empty(&self) -> bool {
186 self.len() == 0
187 }
188
189 /// Returns an iterator over the slice.
190 /// # Example
191 ///
192 /// ```
193 /// use random_wheel::RandomWheel;
194 ///
195 /// let mut rw = RandomWheel::new();
196 ///
197 /// rw.push(1., 'r');
198 /// rw.push(1., 'c');
199 /// rw.push(1., 'a');
200 ///
201 /// let mut iter = rw.iter();
202 ///
203 /// assert_eq!(iter.next(), Some(&(1.0, 'r')));
204 /// assert_eq!(iter.next(), Some(&(1.0, 'c')));
205 /// assert_eq!(iter.next(), Some(&(1.0, 'a')));
206 /// assert_eq!(iter.next(), None);
207 /// ```
208 pub fn iter(&self) -> Iter<(f32, T)> {
209 self.cards.iter()
210 }
211
212 /// Returns an iterator that allows modifying each value.
213 /// # Example
214 ///
215 /// ```
216 /// use random_wheel::RandomWheel;
217 ///
218 /// let mut rw = RandomWheel::new();
219 ///
220 /// rw.push(1., 'r');
221 /// rw.push(1., 'c');
222 /// rw.push(1., 'a');
223 ///
224 /// for a in &mut rw.iter_mut() {
225 /// a.1 = 'm';
226 /// }
227 ///
228 /// assert_eq!(rw.peek(), Some((1., &'m')));
229 /// ```
230 pub fn iter_mut(&mut self) -> IterMut<(f32, T)> {
231 self.cards.iter_mut()
232 }
233
234 /// add an element associated with a probability.
235 /// # Example
236 ///
237 /// ```
238 /// use random_wheel::RandomWheel;
239 ///
240 /// let mut rw = RandomWheel::new();
241 ///
242 /// rw.push(1., 'r');
243 /// rw.push(1., 'c');
244 /// rw.push(1., 'a');
245 ///
246 /// assert_eq!(rw.len(), 3);
247 /// ```
248 pub fn push(&mut self, proba: f32, data: T) {
249
250 assert!(proba > 0.0, "proba {} is lower or equal to zero!", proba);
251 self.cards.push_back((proba, data));
252 self.proba_sum += proba;
253 if self.proba_sum.is_infinite() {
254 panic!("Probability sum reached an Inf value!");
255 }
256 }
257
258 /// Will recompute the probabilities sum
259 /// use it when you iterate through this vector and change proba values
260 pub fn compute_proba_sum(&mut self) {
261
262 let mut sum = 0.0;
263 for &(proba, _) in self.cards.iter() {
264
265 assert!(proba > 0.0, "proba {} is lower or equal to zero!", proba);
266 sum += proba;
267 }
268 self.proba_sum = sum;
269 if self.proba_sum.is_infinite() {
270 panic!("Probability sum reached an Inf value!");
271 }
272 }
273
274 /// returns total of luck you pushed.
275 /// # Example
276 ///
277 /// ```
278 /// use random_wheel::RandomWheel;
279 ///
280 /// let mut rw = RandomWheel::new();
281 ///
282 /// rw.push(1.5, 'r');
283 /// rw.push(2., 'c');
284 /// rw.push(3., 'a');
285 ///
286 /// assert_eq!(rw.proba_sum(), 6.5);
287 /// ```
288 pub fn proba_sum(&self) -> f32 {
289 self.proba_sum
290 }
291
292 /// returns a random distance to browser between 0 and the probabilities sum.
293 fn gen_random_dist(&self) -> f32 {
294
295 match self.proba_sum {
296
297 sum if sum > 0. => rand::thread_rng().gen_range(0., sum),
298 _ => 0.
299 }
300 }
301
302 /// returns a random index in self.cards.
303 fn get_random_index(&self) -> Option<usize> {
304
305 if self.is_empty() == false {
306
307 let mut dist = self.gen_random_dist();
308 for (id, &(ref proba, _)) in self.cards.iter().enumerate() {
309
310 dist -= *proba;
311 if dist <= 0. {
312 return Some(id);
313 }
314 }
315 None
316 }
317 else { None }
318 }
319
320 /// returns a ref to the randomly peeked element with
321 /// it's probality to be peeked.
322 /// # Example
323 ///
324 /// ```
325 /// use random_wheel::RandomWheel;
326 ///
327 /// let mut rw = RandomWheel::new();
328 ///
329 /// rw.push(1., 'r');
330 ///
331 /// assert_eq!(rw.peek(), Some((1.0, &'r')));
332 /// assert_eq!(rw.peek(), Some((1.0, &'r')));
333 /// ```
334 pub fn peek(&self) -> Option<(f32, &T)> {
335
336 if let Some(index) = self.get_random_index() {
337
338 if let Some(&(proba, ref data)) = self.cards.get(index) {
339 Some((proba, data))
340 }
341 else { None }
342 }
343 else { None }
344 }
345
346 /// returns a ref to the randomly peeked element with
347 /// it's probality to be peeked.
348 /// # Example
349 ///
350 /// ```
351 /// use random_wheel::RandomWheel;
352 ///
353 /// let mut rw = RandomWheel::new();
354 ///
355 /// rw.push(1., 'r');
356 ///
357 /// match rw.peek_mut() {
358 /// Some((_, val)) => *val = 'b',
359 /// None => {}
360 /// }
361 ///
362 /// assert_eq!(rw.peek(), Some((1.0, &'b')));
363 /// ```
364 pub fn peek_mut(&mut self) -> Option<(f32, &mut T)> {
365
366 if let Some(index) = self.get_random_index() {
367
368 if let Some(&mut (proba, ref mut data)) = self.cards.get_mut(index) {
369 Some((proba, data))
370 }
371 else { None }
372 }
373 else { None }
374 }
375
376 /// removes a randomly peeked element and return it with
377 /// it's probality to be peeked.
378 /// # Example
379 ///
380 /// ```
381 /// use random_wheel::RandomWheel;
382 ///
383 /// let mut rw = RandomWheel::new();
384 ///
385 /// rw.push(1., 'r');
386 ///
387 /// assert_eq!(rw.pop(), Some((1.0, 'r')));
388 ///
389 /// // once you pop the value, it doesn't exist anymore
390 /// assert_eq!(rw.peek(), None);
391 /// assert_eq!(rw.pop(), None);
392 /// ```
393 pub fn pop(&mut self) -> Option<(f32, T)> {
394
395 if let Some(index) = self.get_random_index() {
396
397 if let Some((proba, data)) = self.cards.remove(index) {
398
399 self.proba_sum -= proba;
400 Some((proba, data))
401 }
402 else { None }
403 }
404 else { None }
405 }
406}