use crate::prelude::*;
macro_rules! sum {
($h:ident,) => ($h);
($h:ident, $($t:ident,)*) => ($h + sum!($($t,)*));
}
#[non_exhaustive]
pub struct OneOfOnceArities;
macro_rules! one_of_once_with_arity {
($arity:ident: $($value_i:ident)+) => (
#[allow(clippy::too_many_arguments)]
pub fn $arity<T>(
self,
$($value_i: T,)*
) -> impl DieOnce<T> {
one_of_die_once().$arity($(dice::just_once($value_i),)*)
}
)
}
impl OneOfOnceArities {
one_of_once_with_arity! { two:
value_0
value_1
}
one_of_once_with_arity! { three:
value_0
value_1
value_2
}
one_of_once_with_arity! { four:
value_0
value_1
value_2
value_3
}
one_of_once_with_arity! { five:
value_0
value_1
value_2
value_3
value_4
}
one_of_once_with_arity! { six:
value_0
value_1
value_2
value_3
value_4
value_5
}
one_of_once_with_arity! { seven:
value_0
value_1
value_2
value_3
value_4
value_5
value_6
}
one_of_once_with_arity! { eight:
value_0
value_1
value_2
value_3
value_4
value_5
value_6
value_7
}
one_of_once_with_arity! { nine:
value_0
value_1
value_2
value_3
value_4
value_5
value_6
value_7
value_8
}
}
pub fn one_of_once() -> OneOfOnceArities {
OneOfOnceArities {}
}
#[non_exhaustive]
pub struct WeightedOneOfOnceArities;
macro_rules! weighted_one_of_once_with_arity {
($arity:ident: $($weight_i:ident, $value_i:ident)+) => (
#[allow(clippy::too_many_arguments)]
pub fn $arity<T>(
self,
$(($weight_i, $value_i): (u32, T),)*
) -> impl DieOnce<T> {
weighted_one_of_die_once().$arity($(($weight_i, dice::just_once($value_i)),)*)
}
)
}
impl WeightedOneOfOnceArities {
weighted_one_of_once_with_arity! { two:
weight_0, value_0
weight_1, value_1
}
weighted_one_of_once_with_arity! { three:
weight_0, value_0
weight_1, value_1
weight_2, value_2
}
weighted_one_of_once_with_arity! { four:
weight_0, value_0
weight_1, value_1
weight_2, value_2
weight_3, value_3
}
weighted_one_of_once_with_arity! { five:
weight_0, value_0
weight_1, value_1
weight_2, value_2
weight_3, value_3
weight_4, value_4
}
weighted_one_of_once_with_arity! { six:
weight_0, value_0
weight_1, value_1
weight_2, value_2
weight_3, value_3
weight_4, value_4
weight_5, value_5
}
weighted_one_of_once_with_arity! { seven:
weight_0, value_0
weight_1, value_1
weight_2, value_2
weight_3, value_3
weight_4, value_4
weight_5, value_5
weight_6, value_6
}
weighted_one_of_once_with_arity! { eight:
weight_0, value_0
weight_1, value_1
weight_2, value_2
weight_3, value_3
weight_4, value_4
weight_5, value_5
weight_6, value_6
weight_7, value_7
}
weighted_one_of_once_with_arity! { nine:
weight_0, value_0
weight_1, value_1
weight_2, value_2
weight_3, value_3
weight_4, value_4
weight_5, value_5
weight_6, value_6
weight_7, value_7
weight_8, value_8
}
}
pub fn weighted_one_of_once() -> WeightedOneOfOnceArities {
WeightedOneOfOnceArities {}
}
#[non_exhaustive]
pub struct OneOfArities;
macro_rules! one_of_with_arity {
($arity:ident: $($value_i:ident)+) => (
#[allow(clippy::too_many_arguments)]
pub fn $arity<T>(
self,
$($value_i: T,)*
) -> impl Die<T>
where
T: Clone,
{
one_of_die().$arity($(dice::just($value_i),)*)
}
)
}
impl OneOfArities {
one_of_with_arity! { two:
value_0
value_1
}
one_of_with_arity! { three:
value_0
value_1
value_2
}
one_of_with_arity! { four:
value_0
value_1
value_2
value_3
}
one_of_with_arity! { five:
value_0
value_1
value_2
value_3
value_4
}
one_of_with_arity! { six:
value_0
value_1
value_2
value_3
value_4
value_5
}
one_of_with_arity! { seven:
value_0
value_1
value_2
value_3
value_4
value_5
value_6
}
one_of_with_arity! { eight:
value_0
value_1
value_2
value_3
value_4
value_5
value_6
value_7
}
one_of_with_arity! { nine:
value_0
value_1
value_2
value_3
value_4
value_5
value_6
value_7
value_8
}
}
pub fn one_of() -> OneOfArities {
OneOfArities {}
}
#[non_exhaustive]
pub struct WeightedOneOfArities;
macro_rules! weighted_one_of_with_arity {
($arity:ident: $($weight_i:ident, $value_i:ident)+) => (
#[allow(clippy::too_many_arguments)]
pub fn $arity<T>(
self,
$(($weight_i, $value_i): (u32, T),)*
) -> impl Die<T>
where
T: Clone,
{
weighted_one_of_die().$arity($(($weight_i, dice::just($value_i)),)*)
}
)
}
impl WeightedOneOfArities {
weighted_one_of_with_arity! { two:
weight_0, value_0
weight_1, value_1
}
weighted_one_of_with_arity! { three:
weight_0, value_0
weight_1, value_1
weight_2, value_2
}
weighted_one_of_with_arity! { four:
weight_0, value_0
weight_1, value_1
weight_2, value_2
weight_3, value_3
}
weighted_one_of_with_arity! { five:
weight_0, value_0
weight_1, value_1
weight_2, value_2
weight_3, value_3
weight_4, value_4
}
weighted_one_of_with_arity! { six:
weight_0, value_0
weight_1, value_1
weight_2, value_2
weight_3, value_3
weight_4, value_4
weight_5, value_5
}
weighted_one_of_with_arity! { seven:
weight_0, value_0
weight_1, value_1
weight_2, value_2
weight_3, value_3
weight_4, value_4
weight_5, value_5
weight_6, value_6
}
weighted_one_of_with_arity! { eight:
weight_0, value_0
weight_1, value_1
weight_2, value_2
weight_3, value_3
weight_4, value_4
weight_5, value_5
weight_6, value_6
weight_7, value_7
}
weighted_one_of_with_arity! { nine:
weight_0, value_0
weight_1, value_1
weight_2, value_2
weight_3, value_3
weight_4, value_4
weight_5, value_5
weight_6, value_6
weight_7, value_7
weight_8, value_8
}
}
pub fn weighted_one_of() -> WeightedOneOfArities {
WeightedOneOfArities {}
}
#[non_exhaustive]
pub struct OneOfDieOnceArities;
macro_rules! one_of_die_once_with_arity {
($n:expr, $arity:ident: $($i:expr, $die_i:ident)+) => (
#[allow(clippy::too_many_arguments)]
pub fn $arity<T>(
self,
$($die_i: impl DieOnce<T>,)*
) -> impl DieOnce<T> {
dice::from_fn_once(move |mut fate| {
let choice = fate.next_number() % $n;
match choice {
$($i => fate.roll($die_i),)*
_ => panic!(),
}
})
}
)
}
impl OneOfDieOnceArities {
one_of_die_once_with_arity! { 2, two:
0, die_0
1, die_1
}
one_of_die_once_with_arity! { 3, three:
0, die_0
1, die_1
2, die_2
}
one_of_die_once_with_arity! { 4, four:
0, die_0
1, die_1
2, die_2
3, die_3
}
one_of_die_once_with_arity! { 5, five:
0, die_0
1, die_1
2, die_2
3, die_3
4, die_4
}
one_of_die_once_with_arity! { 6, six:
0, die_0
1, die_1
2, die_2
3, die_3
4, die_4
5, die_5
}
one_of_die_once_with_arity! { 7, seven:
0, die_0
1, die_1
2, die_2
3, die_3
4, die_4
5, die_5
6, die_6
}
one_of_die_once_with_arity! { 8, eight:
0, die_0
1, die_1
2, die_2
3, die_3
4, die_4
5, die_5
6, die_6
7, die_7
}
one_of_die_once_with_arity! { 9, nine:
0, die_0
1, die_1
2, die_2
3, die_3
4, die_4
5, die_5
6, die_6
7, die_7
8, die_8
}
}
pub fn one_of_die_once() -> OneOfDieOnceArities {
OneOfDieOnceArities {}
}
#[non_exhaustive]
pub struct WeightedOneOfDieOnceArities;
macro_rules! weighted_one_of_die_once_with_arity {
($n:expr, $arity:ident: $($i:expr, $weight_i:ident, $die_i:ident)+) => (
#[allow(clippy::too_many_arguments)]
pub fn $arity<T>(
self,
$(($weight_i, $die_i): (u32, impl DieOnce<T>),)*
) -> impl DieOnce<T> {
$(let $weight_i = u64::from($weight_i);)*
let total_weight = sum!($($weight_i,)*);
dice::from_fn_once(move |mut fate| {
if total_weight == 0 {
let choice = fate.next_number() % $n;
match choice {
$($i => fate.roll($die_i),)*
_ => panic!(),
}
} else {
let choice = fate.next_number() % total_weight;
$(
if choice < $weight_i {
return fate.roll($die_i);
}
#[allow(unused_variables)]
let choice = choice - $weight_i;
)*
unreachable!()
}
})
}
)
}
impl WeightedOneOfDieOnceArities {
weighted_one_of_die_once_with_arity! { 2, two:
0, weight_0, value_0
1, weight_1, value_1
}
weighted_one_of_die_once_with_arity! { 3, three:
0, weight_0, value_0
1, weight_1, value_1
2, weight_2, value_2
}
weighted_one_of_die_once_with_arity! { 4, four:
0, weight_0, value_0
1, weight_1, value_1
2, weight_2, value_2
3, weight_3, value_3
}
weighted_one_of_die_once_with_arity! { 5, five:
0, weight_0, value_0
1, weight_1, value_1
2, weight_2, value_2
3, weight_3, value_3
4, weight_4, value_4
}
weighted_one_of_die_once_with_arity! { 6, six:
0, weight_0, value_0
1, weight_1, value_1
2, weight_2, value_2
3, weight_3, value_3
4, weight_4, value_4
5, weight_5, value_5
}
weighted_one_of_die_once_with_arity! { 7, seven:
0, weight_0, value_0
1, weight_1, value_1
2, weight_2, value_2
3, weight_3, value_3
4, weight_4, value_4
5, weight_5, value_5
6, weight_6, value_6
}
weighted_one_of_die_once_with_arity! { 8, eight:
0, weight_0, value_0
1, weight_1, value_1
2, weight_2, value_2
3, weight_3, value_3
4, weight_4, value_4
5, weight_5, value_5
6, weight_6, value_6
7, weight_7, value_7
}
weighted_one_of_die_once_with_arity! { 9, nine:
0, weight_0, value_0
1, weight_1, value_1
2, weight_2, value_2
3, weight_3, value_3
4, weight_4, value_4
5, weight_5, value_5
6, weight_6, value_6
7, weight_7, value_7
8, weight_8, value_8
}
}
pub fn weighted_one_of_die_once() -> WeightedOneOfDieOnceArities {
WeightedOneOfDieOnceArities {}
}
#[non_exhaustive]
pub struct OneOfDieArities;
macro_rules! one_of_die_with_arity {
($n:expr, $arity:ident: $($i:expr, $die_i:ident)+) => (
#[allow(clippy::too_many_arguments)]
pub fn $arity<T>(
self,
$($die_i: impl Die<T>,)*
) -> impl Die<T> {
dice::from_fn(move |mut fate| {
let choice = fate.next_number() % $n;
match choice {
$($i => fate.roll(&$die_i),)*
_ => panic!(),
}
})
}
)
}
impl OneOfDieArities {
one_of_die_with_arity! { 2, two:
0, die_0
1, die_1
}
one_of_die_with_arity! { 3, three:
0, die_0
1, die_1
2, die_2
}
one_of_die_with_arity! { 4, four:
0, die_0
1, die_1
2, die_2
3, die_3
}
one_of_die_with_arity! { 5, five:
0, die_0
1, die_1
2, die_2
3, die_3
4, die_4
}
one_of_die_with_arity! { 6, six:
0, die_0
1, die_1
2, die_2
3, die_3
4, die_4
5, die_5
}
one_of_die_with_arity! { 7, seven:
0, die_0
1, die_1
2, die_2
3, die_3
4, die_4
5, die_5
6, die_6
}
one_of_die_with_arity! { 8, eight:
0, die_0
1, die_1
2, die_2
3, die_3
4, die_4
5, die_5
6, die_6
7, die_7
}
one_of_die_with_arity! { 9, nine:
0, die_0
1, die_1
2, die_2
3, die_3
4, die_4
5, die_5
6, die_6
7, die_7
8, die_8
}
}
pub fn one_of_die() -> OneOfDieArities {
OneOfDieArities {}
}
#[non_exhaustive]
pub struct WeightedOneOfDieArities;
macro_rules! weighted_one_of_die_with_arity {
($n:expr, $arity:ident: $($i:expr, $weight_i:ident, $die_i:ident)+) => (
#[allow(clippy::too_many_arguments)]
pub fn $arity<T>(
self,
$(($weight_i, $die_i): (u32, impl Die<T>),)*
) -> impl Die<T> {
$(let $weight_i = u64::from($weight_i);)*
let total_weight = sum!($($weight_i,)*);
dice::from_fn(move |mut fate| {
if total_weight == 0 {
let choice = fate.next_number() % $n;
match choice {
$($i => fate.roll(&$die_i),)*
_ => panic!(),
}
} else {
let choice = fate.next_number() % total_weight;
$(
if choice < $weight_i {
return fate.roll(&$die_i);
}
#[allow(unused_variables)]
let choice = choice - $weight_i;
)*
unreachable!()
}
})
}
)
}
impl WeightedOneOfDieArities {
weighted_one_of_die_with_arity! { 2, two:
0, weight_0, value_0
1, weight_1, value_1
}
weighted_one_of_die_with_arity! { 3, three:
0, weight_0, value_0
1, weight_1, value_1
2, weight_2, value_2
}
weighted_one_of_die_with_arity! { 4, four:
0, weight_0, value_0
1, weight_1, value_1
2, weight_2, value_2
3, weight_3, value_3
}
weighted_one_of_die_with_arity! { 5, five:
0, weight_0, value_0
1, weight_1, value_1
2, weight_2, value_2
3, weight_3, value_3
4, weight_4, value_4
}
weighted_one_of_die_with_arity! { 6, six:
0, weight_0, value_0
1, weight_1, value_1
2, weight_2, value_2
3, weight_3, value_3
4, weight_4, value_4
5, weight_5, value_5
}
weighted_one_of_die_with_arity! { 7, seven:
0, weight_0, value_0
1, weight_1, value_1
2, weight_2, value_2
3, weight_3, value_3
4, weight_4, value_4
5, weight_5, value_5
6, weight_6, value_6
}
weighted_one_of_die_with_arity! { 8, eight:
0, weight_0, value_0
1, weight_1, value_1
2, weight_2, value_2
3, weight_3, value_3
4, weight_4, value_4
5, weight_5, value_5
6, weight_6, value_6
7, weight_7, value_7
}
weighted_one_of_die_with_arity! { 9, nine:
0, weight_0, value_0
1, weight_1, value_1
2, weight_2, value_2
3, weight_3, value_3
4, weight_4, value_4
5, weight_5, value_5
6, weight_6, value_6
7, weight_7, value_7
8, weight_8, value_8
}
}
pub fn weighted_one_of_die() -> WeightedOneOfDieArities {
WeightedOneOfDieArities {}
}
pub fn one_of_vec_once<T>(mut values: Vec<T>) -> impl DieOnce<T> {
dice::from_fn_once(move |mut fate| {
let choice = (fate.next_number() as usize) % values.len();
values.swap_remove(choice)
})
}
pub fn one_of_vec<T>(values: Vec<T>) -> impl Die<T>
where
T: Clone,
{
dice::from_fn(move |mut fate| {
let choice = (fate.next_number() as usize) % values.len();
values[choice].clone()
})
}
pub fn one_of_slice<T>(values: &'_ [T]) -> impl Die<T> + '_
where
T: Clone,
{
dice::from_fn(move |mut fate| {
let choice = (fate.next_number() as usize) % values.len();
values[choice].clone()
})
}
#[cfg(test)]
mod tests {
use crate::prelude::*;
#[test]
fn weighted_one_of_die_once_does_not_panic() {
Dicetest::repeatedly().run(|mut fate| {
let die = dice::just(());
let [w1, w2, w3, w4, w5, w6, w7, w8, w9] = fate.roll(dice::array(dice::u32(..)));
fate.roll(dice::weighted_one_of_die_once().two((w1, &die), (w2, &die)));
fate.roll(dice::weighted_one_of_die_once().three((w1, &die), (w2, &die), (w3, &die)));
fate.roll(dice::weighted_one_of_die_once().four(
(w1, &die),
(w2, &die),
(w3, &die),
(w4, &die),
));
fate.roll(dice::weighted_one_of_die_once().five(
(w1, &die),
(w2, &die),
(w3, &die),
(w4, &die),
(w5, &die),
));
fate.roll(dice::weighted_one_of_die_once().six(
(w1, &die),
(w2, &die),
(w3, &die),
(w4, &die),
(w5, &die),
(w6, &die),
));
fate.roll(dice::weighted_one_of_die_once().seven(
(w1, &die),
(w2, &die),
(w3, &die),
(w4, &die),
(w5, &die),
(w6, &die),
(w7, &die),
));
fate.roll(dice::weighted_one_of_die_once().eight(
(w1, &die),
(w2, &die),
(w3, &die),
(w4, &die),
(w5, &die),
(w6, &die),
(w7, &die),
(w8, &die),
));
fate.roll(dice::weighted_one_of_die_once().nine(
(w1, &die),
(w2, &die),
(w3, &die),
(w4, &die),
(w5, &die),
(w6, &die),
(w7, &die),
(w8, &die),
(w9, &die),
));
})
}
#[test]
fn weighted_one_of_die_does_not_panic() {
Dicetest::repeatedly().run(|mut fate| {
let die = dice::just(());
let [w1, w2, w3, w4, w5, w6, w7, w8, w9] = fate.roll(dice::array(dice::u32(..)));
fate.roll(dice::weighted_one_of_die().two((w1, &die), (w2, &die)));
fate.roll(dice::weighted_one_of_die().three((w1, &die), (w2, &die), (w3, &die)));
fate.roll(dice::weighted_one_of_die().four(
(w1, &die),
(w2, &die),
(w3, &die),
(w4, &die),
));
fate.roll(dice::weighted_one_of_die().five(
(w1, &die),
(w2, &die),
(w3, &die),
(w4, &die),
(w5, &die),
));
fate.roll(dice::weighted_one_of_die().six(
(w1, &die),
(w2, &die),
(w3, &die),
(w4, &die),
(w5, &die),
(w6, &die),
));
fate.roll(dice::weighted_one_of_die().seven(
(w1, &die),
(w2, &die),
(w3, &die),
(w4, &die),
(w5, &die),
(w6, &die),
(w7, &die),
));
fate.roll(dice::weighted_one_of_die().eight(
(w1, &die),
(w2, &die),
(w3, &die),
(w4, &die),
(w5, &die),
(w6, &die),
(w7, &die),
(w8, &die),
));
fate.roll(dice::weighted_one_of_die().nine(
(w1, &die),
(w2, &die),
(w3, &die),
(w4, &die),
(w5, &die),
(w6, &die),
(w7, &die),
(w8, &die),
(w9, &die),
));
})
}
}