use rand::prelude::ThreadRng;
use rand::seq::SliceRandom;
use rand::thread_rng;
#[derive(Debug)]
pub struct Dispenser {
seq: Vec<usize>,
rng: ThreadRng,
}
impl Dispenser {
pub fn new(len: usize) -> Self {
let mut disp = Self {
seq: (0..len).collect(),
rng: thread_rng(),
};
disp.shuffle();
disp
}
pub fn len(&self) -> usize {
self.seq.len()
}
pub fn make_hand<'h, T>(&mut self, deck: &'h [T]) -> Option<Hand<'h, T>> {
if deck.len() != self.len() {
None
} else {
Some(self.make_hand_unchecked(deck))
}
}
pub fn make_hand_unchecked<'h, T>(&mut self, deck: &'h [T]) -> Hand<'h, T> {
let b: Box<[usize]> = self.seq.clone().into_boxed_slice();
self.shuffle();
Hand::new(b, deck)
}
fn shuffle(&mut self) {
self.seq.shuffle(&mut self.rng);
}
}
#[derive(Debug)]
pub struct Hand<'h, T>(Box<[usize]>, &'h [T]);
impl<'h, T> Hand<'h, T> {
pub fn new(choices: Box<[usize]>, elements: &'h [T]) -> Hand<'h, T> {
Hand(choices, elements)
}
pub fn choose(&self, idx: usize) -> Option<&T> {
if let Some(u) = self.0.get(idx) {
if let Some(t) = self.1.get(u.to_owned()) {
return Some(t);
}
}
None
}
pub fn len(&self) -> usize {
self.0.len()
}
}
#[test]
fn numbers() {
let choices = (1..10).collect::<Vec<u8>>();
let mut dispenser = Dispenser::new(choices.len());
let hand1 = dispenser.make_hand_unchecked(&choices);
let hand2 = dispenser.make_hand_unchecked(&choices);
let hand3 = dispenser.make_hand_unchecked(&choices);
let choice1 = hand1.choose(0).unwrap();
assert!(choices.contains(choice1));
let choice2 = hand2.choose(0).unwrap();
assert!(choices.contains(choice2));
let choice3 = hand1.choose(0).unwrap();
assert!(choices.contains(choice3));
dbg!(hand1, hand2, hand3);
}
#[test]
fn enums() {
#[derive(Eq, PartialEq, Debug)]
enum Something {
A,
B,
C,
D,
}
let choices: Vec<Something> = vec![Something::A, Something::B, Something::C, Something::D];
let mut dispenser = Dispenser::new(choices.len());
let hand1 = dispenser.make_hand_unchecked(&choices);
let hand2 = dispenser.make_hand_unchecked(&choices);
let choice1 = hand1.choose(0).unwrap();
let choice2 = hand2.choose(0).unwrap();
assert!(choices.contains(choice1));
assert!(choices.contains(choice2));
dbg!(choice1, choice2);
dbg!(hand1, hand2);
}
#[test]
fn some_and_none() {
let choices = vec![0];
let mut dispenser = Dispenser::new(choices.len());
let za_hando = dispenser.make_hand_unchecked(&choices);
assert!(za_hando.choose(0).is_some());
assert!(za_hando.choose(1).is_none());
}