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