Skip to main content

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}