tudelft_dice_example/
lib.rs

1#![deny(warnings)]
2#![deny(missing_docs)]
3//! This library simulates dice rolls
4
5use rand::prelude::*;
6use std::num::ParseIntError;
7use thiserror::Error;
8
9#[derive(Debug, PartialEq)]
10struct DiceRoll {
11    number: usize,
12    sides: usize,
13}
14
15/// The error that [`dice`] can give
16#[derive(Debug, PartialEq, Eq, Error)]
17pub enum RollError {
18    /// The syntax is incorrect
19    #[error("syntax incorrect")]
20    IncorrectSyntax,
21    /// Not a number
22    #[error("couldn't parse int")]
23    ParseNumber(#[from] ParseIntError),
24}
25
26fn parse(s: &str) -> Result<DiceRoll, RollError> {
27    let parts = s.split('d').collect::<Vec<_>>();
28
29    if parts.len() != 2 {
30        return Err(RollError::IncorrectSyntax);
31    }
32
33    Ok(DiceRoll {
34        number: parts[0].parse()?,
35        sides: parts[1].parse()?,
36    })
37}
38
39fn throw_dice(s: &DiceRoll) -> Vec<usize> {
40    let mut rng = rand::thread_rng();
41
42    (0..s.number).map(|_| rng.gen_range(1..=s.sides)).collect()
43}
44
45/// # Dice Funcion
46///
47/// The dice function simulates a diceroll (error is [`RollError`])
48pub fn dice(s: &str) -> Result<Vec<usize>, RollError> {
49    let d = parse(s)?;
50
51    Ok(throw_dice(&d))
52}
53
54
55#[cfg(test)]
56mod tests {
57    use crate::{dice, parse, DiceRoll, RollError};
58
59
60    #[test]
61    fn smoke() {
62        assert!(dice("1d6").unwrap()[0] < 7);
63    }
64
65    #[test]
66    fn test_6d1() {
67        assert_eq!(dice("6d1").unwrap(), vec![1; 6], "should be all ones {}", 1);
68    }
69
70    #[test]
71    fn test_parse_1d6() {
72        assert_eq!(parse("1d6"), Ok(DiceRoll { number: 1, sides: 6 }));
73        assert_eq!(parse("6d6"), Ok(DiceRoll { number: 6, sides: 6 }));
74        assert_eq!(parse("1d12"), Ok(DiceRoll { number: 1, sides: 12 }));
75        assert_eq!(parse("1b12"), Err(RollError::IncorrectSyntax));
76        assert!(matches!(
77            dice("xd12"), 
78            Err(RollError::ParseNumber(_))
79        ));
80        assert!(matches!(
81            dice("12dx"), 
82            Err(RollError::ParseNumber(_))
83        ));
84    }
85}
86