elevate_lib/
person.rs

1//Import standard/imported libraries
2use std::fmt;
3use rand::Rng;
4use rand::distributions::{Distribution, Uniform, Bernoulli};
5
6/// # Person struct
7///
8/// A `Person` is aggregated by floors and elevators, and transported between floors
9/// by elevators. The person struct generally should not be directly instantiated;
10/// instead it should be managed in aggregate via the `Building` type.
11#[derive(Clone)]
12pub struct Person {
13    pub floor_on: usize,
14    pub floor_to: usize,
15    pub is_leaving: bool,
16    pub wait_time: usize,
17    pub p_out: f64,
18    pub p_tip: f64,
19    dst_out: Bernoulli,
20    dst_tip: Bernoulli
21}
22
23/// # Person type implementation
24///
25/// The following functions are used by `Elevator`/`Elevators`, `Floor`/`Floors`, and
26/// `Building` types to randomly generate the behavior of `Person`s
27impl Person {
28    /// Initialize a new person given that persons probability of leaving, the number of
29    /// floors in the building, and an Rng implementation to randomize the person's
30    /// destination floor
31    ///
32    /// ### Example
33    ///
34    /// ```
35    /// let p_out: f64 = 0.05_f64; //Must be between 0 and 1
36    /// let p_tip: f64 = 0.2_f64; //Must be between 0 and 1
37    /// let num_floors: usize = 5_usize;
38    /// let my_rng = rand::thread_rng(); //From rand library
39    /// let my_pers: Person = Person::from(p_out, num_floors, &mut my_rng);
40    /// ```
41    pub fn from(p_out: f64, p_tip: f64, num_floors: usize, mut rng: &mut impl Rng) -> Person {
42        let dst_to = Uniform::new(0_usize, num_floors);
43        let floor_to: usize = dst_to.sample(&mut rng);
44        Person {
45            floor_on: 0_usize,
46            floor_to: floor_to,
47            is_leaving: false,
48            wait_time: 0_usize,
49            p_out: p_out,
50            dst_out: Bernoulli::new(p_out).unwrap(),
51            p_tip: p_tip,
52            dst_tip: Bernoulli::new(p_tip).unwrap()
53        }
54    }
55
56    /// Sample a person's `dst_out` distribution to update the person's `is_leaving`
57    /// property randomly and return the result as a bool.  Or if the person is already
58    /// leaving then return the property as is.
59    pub fn gen_is_leaving(&mut self, mut rng: &mut impl Rng) -> bool {
60        //Check if the is_leaving boolean is true, if so return it
61        if self.is_leaving {
62            return self.is_leaving;
63        }
64
65        //If the person is not leaving, then randomly generate whether they wish to leave
66        let pers_is_leaving: bool = self.dst_out.sample(&mut rng);
67        if pers_is_leaving {
68            self.floor_to = 0_usize;
69            self.is_leaving = pers_is_leaving;
70        }
71        self.is_leaving
72    }
73
74    /// Sample a person's `dst_tip` distribution to determine whether or not they will
75    /// decide to tip.
76    pub fn gen_tip(&self, mut rng: &mut impl Rng) -> bool {
77        self.dst_tip.sample(&mut rng)
78    }
79
80    /// Increment a person's `wait_time` property by `1_usize`.  Generally this should be
81    /// called by `Elevator`/`Elevators`, `Floor`/`Floors`, and `Building` types aggregating
82    /// `Person`s when the `Person` is not at their desired floor.
83    pub fn increment_wait_time(&mut self) {
84        //Increment the person's wait time counter
85        self.wait_time += 1_usize;
86    }
87
88    /// Reset a person's `wait_time` property to `0_usize`.  Generally this should be
89    /// called by `Elevator`/`Elevators`, `Floor`/`Floors`, and `Building` types aggregating
90    /// `Person`s when the `Person` finally reaches their desired floor.
91    pub fn reset_wait_time(&mut self) {
92        //Reset the person's wait time counter
93        self.wait_time = 0_usize;
94    }
95}
96
97impl fmt::Display for Person {
98    /// Format a `Person` as a string.  If a person is not at their desired floor then display
99    /// the person's current and desired floor like so: `Person 2 -> 4`.  If the person is at
100    /// their desired floor then just display their current floor like so: `Person 4`.
101    ///
102    /// ### Example
103    ///
104    /// ```
105    /// println!("{}", my_pers);
106    /// ```
107    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108        let display_str: String = if self.floor_on != self.floor_to {
109            format!("Person {} -> {}", self.floor_on, self.floor_to)
110        } else {
111            format!("Person {}", self.floor_on)
112        };
113        f.write_str(&display_str)
114    }
115}