Allow RngDeck to be passed between threads

main
Clément FRÉVILLE 2 years ago
parent a757241b5d
commit f1564ca6e3

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

Loading…
Cancel
Save