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}