elevate_lib/
floor.rs

1//Import external/standard modules
2use rand::Rng;
3
4//Import source modules
5use crate::person::Person;
6use crate::people::People;
7
8/// # `Floor` struct
9///
10/// A `Floor` is aggregated by buildings.  People travel between them using
11/// elevators.  The floor struct generally should not be directly instantiated;
12/// instead it should be managed in aggregate via the `Building` type.
13#[derive(Clone)]
14pub struct Floor {
15    people: Vec<Person>,
16    pub dest_prob: f64
17}
18
19/// # `Floor` type implementation
20///
21/// The following functions are used by `Building`s and `Floors` implementations.
22impl Floor {
23    /// Initialize a new Floor with a zero destination probability and an empty
24    /// vector of `Person`s.
25    ///
26    /// ## Example
27    ///
28    /// ```
29    /// let my_floor: Floor = Floor::new();
30    /// ```
31    pub fn new() -> Floor {
32        Floor {
33            people: Vec::new(),
34            dest_prob: 0_f64
35        }
36    }
37
38    /// Calculate the probability that a person on the floor leaves during the next
39    /// time step, and return the result as an f64.
40    pub fn get_p_out(&self) -> f64 {
41        //If there is no one on the floor, return 0_f64
42        if self.people.len() == 0 {
43            return 0_f64;
44        }
45
46        //Initialize a p_out variable and a vec for each p_out
47        let mut p_out: f64 = 0_f64;
48        let mut past_p_outs: Vec<f64> = Vec::new();
49
50        //Loop through the people in the floor and iteratively calculate
51        //the p_out value
52        for pers in self.people.iter() {
53            //Calculate the product of each of the past people's inverse
54            //p_out values
55            let inverse_p_outs: f64 = {
56                let mut tmp_inverse_p_outs: f64 = 1_f64;
57                for past_p_out in &past_p_outs {
58                    tmp_inverse_p_outs = tmp_inverse_p_outs * (1_f64 - past_p_out);
59                }
60                tmp_inverse_p_outs
61            };
62
63            //Calculate the summand value based on the person's p_out and
64            //the product of each of the past people's p_out values
65            let tmp_p_out: f64 = pers.p_out * inverse_p_outs;
66
67            //Add the newly calculated value onto the p_out value and then
68            //append the current p_out
69            p_out += tmp_p_out;
70            past_p_outs.push(pers.p_out);
71        }
72
73        //Return the p_out value
74        p_out
75    }
76
77    /// Randomly generate whether anyone on the floor is leaving using each `Person`'s
78    /// `gen_is_leaving` function.
79    pub fn gen_people_leaving(&mut self, rng: &mut impl Rng) {
80        //Loop through the people on the floor and decide if they are leaving
81        for pers in self.people.iter_mut() {
82            //Skip people who are waiting for the elevator
83            if pers.floor_on != pers.floor_to {
84                continue;
85            }
86
87            //Randomly generate whether someone not waiting for the elevator will leave
88            let _is_person_leaving: bool = pers.gen_is_leaving(rng);
89        }
90    }
91
92    /// Remove people from a floor who are currently waiting/not on their desired floor
93    /// and return as a `Vec<Person>`.  This is used when the elevator is on this floor
94    /// and there is an exchange of people between the elevator and the floor.
95    pub fn flush_people_entering_elevator(&mut self) -> Vec<Person> {
96        //Initialize a vector of people for the people entering the elevator
97        let mut people_entering_elevator: Vec<Person> = Vec::new();
98
99        //Loop through the people on the floor and add to the vec
100        let mut removals = 0_usize;
101        for i in 0..self.people.len() {
102            //If the person is not waiting, then skip
103            if self.people[i-removals].floor_on == self.people[i-removals].floor_to {
104                continue;
105            }
106
107            //If the person is waiting, then remove them from the elevator
108            //and add them to the leaving vec, incrementing the removals
109            let person_entering_elevator: Person = self.people.remove(i - removals);
110            people_entering_elevator.push(person_entering_elevator);
111            removals += 1_usize;
112        }
113
114        //Return the vector of people leaving
115        people_entering_elevator
116    }
117
118    /// Remove people entirely who are leaving the building.  This is used exclusively
119    /// on the first floor.
120    pub fn flush_people_leaving_floor(&mut self) -> Vec<Person> {
121        //Initialize a vector of people for the people leaving the floor
122        let mut people_leaving_floor: Vec<Person> = Vec::new();
123
124        //Loop through the people on the floor and add to the vec if leaving
125        let mut removals = 0_usize;
126        for i in 0..self.people.len() {
127            //If the person is not leaving, then skip
128            if !self.people[i-removals].is_leaving {
129                continue;
130            }
131
132            //If the person is leaving, then remove them from the floor
133            //and add them to the leaving vec, incrementing the removals
134            let person_leaving_floor: Person = self.people.remove(i - removals);
135            people_leaving_floor.push(person_leaving_floor);
136            removals += 1_usize;
137        }
138
139        //Return the vector of people leaving
140        people_leaving_floor
141    }
142}
143
144//Implement the extend trait for the floor struct
145impl Extend<Person> for Floor {
146    fn extend<T: IntoIterator<Item=Person>>(&mut self, iter: T) {
147        for pers in iter {
148            self.people.push(pers);
149        }
150    }
151}
152
153//Implement the people trait for the floor struct
154impl People for Floor {
155    /// Generates the number of people among the collection of people who will tip.
156    fn gen_num_tips(&self, rng: &mut impl Rng) -> usize {
157        self.people.gen_num_tips(rng)
158    }
159
160    /// Determines the destination floors for all people on the floor and returns it as
161    /// a vector.
162    fn get_dest_floors(&self) -> Vec<usize> {
163        self.people.get_dest_floors()
164    }
165
166    /// Determines the total number of people on the floor and returns it as a usize.
167    fn get_num_people(&self) -> usize {
168        self.people.get_num_people()
169    }
170
171    /// Determines the number of people waiting on the floor, that is, not at their
172    /// desired floor.
173    fn get_num_people_waiting(&self) -> usize {
174        self.people.get_num_people_waiting()
175    }
176
177    /// Reads the wait times from people waiting on the floor/not at their desired floor
178    /// and aggregates the total into a usize.
179    fn get_aggregate_wait_time(&self) -> usize {
180        self.people.get_aggregate_wait_time()
181    }
182
183    /// Determines whether anyone on the floor are going to a given floor, and returns a
184    /// bool which is true if so, and false if not.
185    fn are_people_going_to_floor(&self, floor_index: usize) -> bool {
186        self.people.are_people_going_to_floor(floor_index)
187    }
188
189    /// Determines whether anyone on the floor is waiting/not at their desired floor, and
190    /// returns a bool which is true if so, and false if not.
191    fn are_people_waiting(&self) -> bool {
192        self.people.are_people_waiting()
193    }
194
195    /// Increments the wait times (by `1_usize`) among all people waiting on the floor/not
196    /// at their desired floor.
197    fn increment_wait_times(&mut self) {
198        //Loop through the people
199        for pers in self.people.iter_mut() {
200            //If the person is not waiting, then skip
201            if pers.floor_on == pers.floor_to {
202                continue;
203            }
204
205            //Increment the person's wait time if they are waiting
206            pers.increment_wait_time();
207        }
208    }
209
210    /// Resets the wait times (to `0_usize`) among all people on the floor who have a nonzero
211    /// wait time and are on their desired floor.
212    fn reset_wait_times(&mut self) {
213        //Loop through the people
214        for pers in self.people.iter_mut() {
215            //If the person is waiting, then skip
216            if pers.floor_on != pers.floor_to {
217                continue;
218            }
219
220            //Reset the person's wait time if they are not waiting
221            pers.reset_wait_time();
222        }
223    }
224}