|
|
|
@ -1,6 +1,6 @@
|
|
|
|
|
use crate::tile::Operator;
|
|
|
|
|
use enum_map::EnumMap;
|
|
|
|
|
use rand::Rng;
|
|
|
|
|
use rand::{thread_rng, Rng};
|
|
|
|
|
|
|
|
|
|
type DeckSize = u16;
|
|
|
|
|
type DigitDeck = [DeckSize; 19];
|
|
|
|
@ -63,40 +63,37 @@ impl Deck {
|
|
|
|
|
#[derive(Debug, Clone, Default)]
|
|
|
|
|
pub struct RngDeck {
|
|
|
|
|
deck: Deck,
|
|
|
|
|
rng: rand::rngs::ThreadRng,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl RngDeck {
|
|
|
|
|
pub fn new_complete() -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
deck: Deck::new_complete(),
|
|
|
|
|
rng: rand::thread_rng(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Gets a random tile from the deck and remove it from the deck.
|
|
|
|
|
pub fn rand_digit(&mut self) -> Option<i8> {
|
|
|
|
|
let sum = self.deck.digits.iter().sum();
|
|
|
|
|
Self::select_rng(&mut self.rng, sum, self.deck.digits.iter_mut().enumerate())
|
|
|
|
|
.map(|n| n as i8 - 9)
|
|
|
|
|
Self::select_rng(sum, self.deck.digits.iter_mut().enumerate()).map(|n| n as i8 - 9)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Gets a random operator from the deck and remove it from the deck.
|
|
|
|
|
pub fn rand_operator(&mut self) -> Option<Operator> {
|
|
|
|
|
let sum = self.deck.operators.values().sum();
|
|
|
|
|
Self::select_rng(&mut self.rng, sum, self.deck.operators.iter_mut())
|
|
|
|
|
Self::select_rng(sum, self.deck.operators.iter_mut())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Selects a random item from an iterator of (item, count) pairs.
|
|
|
|
|
/// The count is decremented by one if the item is selected.
|
|
|
|
|
fn select_rng<'a, T>(
|
|
|
|
|
rng: &mut rand::rngs::ThreadRng,
|
|
|
|
|
sum: DeckSize,
|
|
|
|
|
it: impl Iterator<Item = (T, &'a mut DeckSize)>,
|
|
|
|
|
) -> Option<T> {
|
|
|
|
|
if sum == 0 {
|
|
|
|
|
return None;
|
|
|
|
|
}
|
|
|
|
|
let mut rng = thread_rng();
|
|
|
|
|
let mut threshold = rng.gen_range(1..=sum);
|
|
|
|
|
for (item, count) in it {
|
|
|
|
|
threshold = threshold.saturating_sub(*count);
|
|
|
|
|