1use anyhow::{Result, ensure};
6use rand::Rng;
7use static_assertions::const_assert;
8
9pub const FACE_MAX: u64 = 1u64 << 56;
11pub const COUNT_MAX: u32 = 100;
13
14const_assert!(FACE_MAX < u64::MAX / COUNT_MAX as u64);
15
16pub fn roll(face: u64, count: u32) -> Result<Vec<u64>> {
21 ensure!(
22 (1..=FACE_MAX).contains(&face),
23 "face must be 1 <= face <= {FACE_MAX}",
24 );
25 ensure!(
26 (1..=COUNT_MAX).contains(&count),
27 "count must be 1 <= count <= {COUNT_MAX}",
28 );
29
30 let mut result = vec![];
31 let mut rng = rand::rng();
32 for _ in 0..count {
33 result.push(rng.random_range(1..=face));
34 }
35
36 Ok(result)
37}
38
39#[cfg(test)]
40mod tests {
41 use super::*;
42
43 #[test]
44 fn dice_6_many_times() {
45 let mut result = roll(6, COUNT_MAX).unwrap();
46 assert_eq!(result.len(), COUNT_MAX as usize);
47
48 result.sort();
50 for x in 1..=6 {
51 assert!(result.binary_search(&x).is_ok());
52 }
53 }
54
55 #[test]
56 #[should_panic]
57 fn dice_invalid_dice() {
58 let _ = roll(FACE_MAX + 1, 1).unwrap();
59 }
60
61 #[test]
62 #[should_panic]
63 fn dice_invalid_count() {
64 let _ = roll(6, COUNT_MAX + 1).unwrap();
65 }
66}