1extern crate rand;
2#[cfg(feature = "serde")]
3#[macro_use]
4extern crate serde;
5
6use rand::{Rng, SeedableRng};
7use rand::distributions::Uniform;
8use rand::rngs::SmallRng;
9use std::num::NonZeroU32;
10
11#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
12#[derive(Debug, Clone)]
13pub struct Die {
14 faces: NonZeroU32,
15}
16
17impl Default for Die {
18 fn default() -> Self {
19 Die { faces: NonZeroU32::new(20).unwrap() }
20 }
21}
22
23impl Die {
24 pub fn new(faces: NonZeroU32) -> Die {
26 Die { faces }
27 }
28
29 pub fn roll(&self) -> u32 {
31 let mut rng = SmallRng::from_entropy();
32
33 rng.sample(Uniform::new_inclusive(1, self.faces().get()))
34 }
35
36 pub fn faces(&self) -> NonZeroU32 {
38 self.faces
39 }
40}
41
42pub fn roll(amount: u32, faces: NonZeroU32) -> Vec<u32> {
57 let die = Die::new(faces);
58 let mut results = Vec::with_capacity(amount as usize);
59
60 for _ in 0..amount {
61 results.push(die.roll());
62 }
63
64 results
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70
71 #[test]
72 fn die_roll_d6() {
73 let faces = NonZeroU32::new(6).unwrap();
74 let d6 = Die::new(faces);
75
76 for _ in 0..99 {
77 let roll = d6.roll();
78 assert!(roll > 0 && roll <= faces.get());
79 }
80 }
81
82 #[test]
83 fn die_roll_d1() {
84 let d1 = Die::new(NonZeroU32::new(1).unwrap());
85
86 assert_eq!(d1.roll(), 1);
87 }
88
89 #[test]
90 fn die_faces() {
91 let d6 = Die::new(NonZeroU32::new(6).unwrap());
92
93 assert_eq!(d6.faces().get(), 6)
94 }
95
96 #[test]
97 fn roll_vector_length_equals_number_of_dice() {
98 let length = roll(3, NonZeroU32::new(6).unwrap()).len();
99
100 assert_eq!(length, 3);
101 }
102
103 #[test]
104 fn roll_vector_contains_numbers_from_valid_range() {
105 let amount = 3;
106 let faces = NonZeroU32::new(6).unwrap();
107
108 for _ in 0..99 {
109 let vec = roll(amount, faces);
110 assert!(vec.iter().all(|v| v <= &faces.get() && v > &0));
111 }
112 }
113
114 #[test]
115 fn roll_zero_dice() {
116 let amount = 0;
117 let faces = NonZeroU32::new(6).unwrap();
118
119 assert_eq!(roll(amount, faces).len(), 0)
120 }
121}