1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
//##################################################################################################
//******************************************* DEPENDENCIES  ****************************************
//##################################################################################################


extern crate rand;


//--------------------------------------------------------------------------------------------------


use dice::Die;
use rand::Rng;
use std::fmt::{Display,Formatter,Result};


//##################################################################################################
//**************************************** STRUCT DECLARATIONS *************************************
//##################################################################################################


//==================================================================================================
/// A die that has numeric values at fixed intervals from each other (e.g. d6, d20, d4, etc).
//==================================================================================================
pub struct NumericDie {

    /// Lowest value present on die
    min_value: usize,                   
    /// Interval between die values
    value_step: usize,                  
    /// Number of values the die may have
    num_sides: usize,                   
    /// Value last rolled; die is initialized with min_value
    current_value: usize,               
    /// Source of randomness
    rng: Box<Rng>,                      
}


//##################################################################################################
//************************************* STRUCT IMPLEMENTATIONS *************************************
//##################################################################################################


//==================================================================================================
impl NumericDie {
//==================================================================================================    


    //==============================================================================================
    /// Pseudo-constructor for NumericDie object.
    //----------------------------------------------------------------------------------------------
    ///
    /// ##### Parameters
    ///  - min       : minimum value die may have
    ///  - step      : interval between values
    ///  - num_sides : number of possible values
    ///  - rng       : optional RNG; if none, defaults to ThreadRng
    ///
    /// ##### Return value
    /// A NumericDie constructed with the given specifications
    //----------------------------------------------------------------------------------------------
    /// # Examples
    /// ```
    /// # extern crate ezra;
    /// extern crate rand;
    /// use ezra::dice::{Die,NumericDie};
    /// use rand::OsRng;
    /// # fn main() {
    ///
    /// // Create a standard six sided die, using the OS's source of randomness
    /// let rng = OsRng::new().unwrap();
    /// let mut die = NumericDie::new(1, 1, 6, Some(Box::new(rng)));
    /// println!("First die roll has value: {}", die.roll().get_value());
    /// # }
    /// ```
    //----------------------------------------------------------------------------------------------
    /// A die can also be created without specifying an RNG. The constructed die will use its own
    /// thread-local RNG by default.
    ///
    /// ```
    /// # extern crate ezra;
    /// # extern crate rand;
    /// # use ezra::dice::NumericDie;
    /// # fn main() {
    /// let die = NumericDie::new(1, 1, 6, None);
    /// # }
    /// ```
    //==============================================================================================

    pub fn new(min: usize, step: usize, num_sides: usize, rng: Option<Box<Rng>>) -> Self {
    
        NumericDie {
            min_value: min,
            value_step: step,
            num_sides: num_sides,
            current_value: min,
            rng: match rng {
                Some(r) => r,
                None => Box::new(rand::thread_rng()),
            },
        }
    }
}


//==================================================================================================
impl Die for NumericDie {
//==================================================================================================

    
    //==============================================================================================
    type ValueType = usize;
    //----------------------------------------------------------------------------------------------
    // Type of value die will have.
    //==============================================================================================


    //==============================================================================================
    fn roll(&mut self) -> &mut Self {
    //----------------------------------------------------------------------------------------------
    // Randomizes value of the die to one of its `num_sides` possible values, and returns itself.
    //----------------------------------------------------------------------------------------------
    // TAKES:   nothing
    //
    // RETURNS: a mutable reference to itself
    //==============================================================================================

        self.current_value = self.min_value + self.value_step * self.rng.gen_range(0, self.num_sides);
        self
    }


    //==============================================================================================
    fn get_value(&self) -> Self::ValueType {
    //----------------------------------------------------------------------------------------------
    // Obtain the current value of the die.
    //----------------------------------------------------------------------------------------------
    // TAKES:   nothing
    //
    // RETURNS: the current value of the die
    //==============================================================================================
    
        self.current_value
    }


    //==============================================================================================
    fn values(&self) -> Vec<Self::ValueType> {
    //----------------------------------------------------------------------------------------------
    // Obtain a list of all possible values a die may have.
    //----------------------------------------------------------------------------------------------
    // TAKES:   nothing
    //
    // RETURNS: vector containing all possible values the die may have
    //==============================================================================================

        let mut result = Vec::new();
        for i in 0..self.num_sides {
            result.push(self.min_value + self.value_step * i);
        }
        result
    }
}


//==================================================================================================
impl Display for NumericDie {
//==================================================================================================


    //==============================================================================================
    fn fmt(&self, f: &mut Formatter) -> Result {
    //----------------------------------------------------------------------------------------------
    // Print the die using a given formatter.
    //----------------------------------------------------------------------------------------------
    // TAKES:   f -> formatter with which to print the die
    //
    // RETURNS: Ok(())   -> printed the die without error
    //          Err(...) -> something went wrong while attempting to print the die
    //==============================================================================================

        write!(f, "{}", self.current_value)
    }
}