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}