1use rand::Rng;
3use rand::distributions::Distribution;
4use statrs::distribution::{Poisson, Binomial};
5
6use crate::person::Person;
8use crate::people::People;
9use crate::floor::Floor;
10use crate::floors::Floors;
11use crate::elevator::Elevator;
12use crate::elevators::Elevators;
13
14const P_OUT: f64 = 0.05_f64;
16
17const P_TIP: f64 = 0.5_f64;
19
20const DST_TIP_TRIALS: u64 = 100_u64;
22const DST_TIP_SUCCESS: f64 = 0.5_f64;
23
24#[derive(Clone)]
30pub struct Building {
31 pub elevators: Vec<Elevator>,
32 pub floors: Vec<Floor>,
33 pub avg_energy: f64,
34 pub avg_wait_time: f64,
35 pub tot_tips: f64,
36 wait_time_denom: usize,
37 p_in: f64,
38 dst_in: Poisson,
39 dst_tip: Binomial
40}
41
42impl Building {
47 pub fn from(num_floors: usize, num_elevators: usize, p_in: f64, energy_up: f64,
70 energy_down: f64, energy_coef: f64) -> Building {
71 let floors: Vec<Floor> = {
73 let mut tmp_floors: Vec<Floor> = Vec::new();
74 for _ in 0_usize..num_floors {
75 let tmp_floor: Floor = Floor::new();
76 tmp_floors.push(tmp_floor);
77 }
78 tmp_floors
79 };
80
81 let elevators: Vec<Elevator> = {
83 let mut tmp_elevators: Vec<Elevator> = Vec::new();
84 for _ in 0_usize..num_elevators {
85 let tmp_elevator: Elevator = Elevator::from(
86 energy_up, energy_down, energy_coef
87 );
88 tmp_elevators.push(tmp_elevator);
89 }
90 tmp_elevators
91 };
92
93 let dst_in = Poisson::new(p_in).unwrap();
95
96 Building {
98 floors: floors,
99 elevators: elevators,
100 avg_energy: 0_f64,
101 avg_wait_time: 0_f64,
102 wait_time_denom: 0_usize,
103 tot_tips: 0_f64,
104 p_in: p_in,
105 dst_in: dst_in,
106 dst_tip: Binomial::new(DST_TIP_SUCCESS, DST_TIP_TRIALS).unwrap()
107 }
108 }
109
110 pub fn update_dest_probabilities(&mut self) {
114 let num_floors: usize = self.floors.len() as usize;
116
117 let dest_floors: Vec<usize> = self.elevators.get_dest_floors();
119
120 for (i, floor) in self.floors.iter_mut().enumerate() {
122 let dest_probability: f64 = if i == 0 {
124 let people_waiting: f64 = {
127 let waiting: f64 = if floor.are_people_waiting() { 1_f64 } else { 0_f64 };
128 let going: f64 = if dest_floors.contains(&i) { 1_f64 } else { 0_f64 };
129 if waiting > going { waiting } else { going }
130 };
131 let p_in: f64 = self.p_in * ((num_floors as f64 - 1_f64)/(num_floors as f64));
132 if people_waiting > p_in { people_waiting } else { p_in }
133 } else {
134 let people_waiting: f64 = {
138 let waiting: f64 = if floor.are_people_waiting() { 1_f64 } else { 0_f64 };
139 let going: f64 = if dest_floors.contains(&i) { 1_f64 } else { 0_f64 };
140 if waiting > going { waiting } else { going }
141 };
142 let p_out: f64 = floor.get_p_out();
143 if people_waiting > p_out { people_waiting } else { p_out }
144 };
145 floor.dest_prob = dest_probability;
146 }
147 }
148
149 pub fn gen_people_arriving(&mut self, mut rng: &mut impl Rng) {
152 let mut arrivals: Vec<Person> = Vec::new();
154
155 for _ in 0_i32..self.dst_in.sample(&mut rng) as i32 {
157 let new_person: Person = Person::from(P_OUT, P_TIP, self.floors.len(), &mut rng);
158 arrivals.push(new_person);
159 }
160
161 self.floors[0].extend(arrivals);
163 }
164
165 pub fn gen_tip_value(&self, num_tips: usize, rng: &mut impl Rng) -> f64 {
167 let mut tip_value: f64 = 0.0_f64;
169
170 for _ in 0..num_tips {
173 tip_value += self.dst_tip.sample(rng) / 100_f64;
174 }
175
176 tip_value
178 }
179
180 pub fn exchange_people_on_elevator(&mut self) {
184 for elevator in self.elevators.iter_mut() {
185 if !elevator.stopped {
187 continue;
188 }
189
190 let floor_index: usize = elevator.floor_on;
192
193 let people_leaving_floor: Vec<Person> = self.floors[floor_index].flush_people_entering_elevator();
195 let mut people_leaving_elevator: Vec<Person> = elevator.flush_people_leaving_elevator();
196
197 let wait_times: usize = people_leaving_elevator.get_aggregate_wait_time();
199 let num_people: usize = people_leaving_elevator.get_num_people();
200 self.avg_wait_time = {
201 let tmp_num: f64 = wait_times as f64 + (self.avg_wait_time * self.wait_time_denom as f64);
202 let tmp_denom: f64 = num_people as f64 + self.wait_time_denom as f64;
203 if tmp_denom == 0_f64 {
204 0_f64 } else {
206 tmp_num / tmp_denom
207 }
208 };
209 self.wait_time_denom += num_people;
210 people_leaving_elevator.reset_wait_times();
211
212 elevator.extend(people_leaving_floor);
214 self.floors[floor_index].extend(people_leaving_elevator);
215 }
216 }
217
218 pub fn flush_and_update_tips(&mut self, rng: &mut impl Rng) {
220 let people_leaving_floor: Vec<Person> = self.floors.flush_first_floor();
221 let num_tips: usize = people_leaving_floor.gen_num_tips(rng);
222 let tip_value: f64 = self.gen_tip_value(num_tips, rng);
223 self.tot_tips += tip_value;
224 }
225
226 pub fn collect_tips(&mut self) -> f64 {
228 let tips: f64 = self.tot_tips;
229 self.tot_tips = 0.0_f64;
230 tips
231 }
232
233 pub fn update_average_energy(&mut self, time_step: i32, energy_spent: f64) {
236 self.avg_energy = {
237 let tmp_num: f64 = (self.avg_energy * time_step as f64) + energy_spent;
238 let tmp_denom: f64 = (time_step + 1_i32) as f64;
239 tmp_num / tmp_denom
240 };
241 }
242
243 pub fn append_elevator(&mut self, energy_up: f64, energy_down: f64, energy_coef: f64) {
245 self.elevators.push(Elevator::from(energy_up, energy_down, energy_coef));
246 }
247}
248
249impl std::fmt::Display for Building {
251 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
259 let mut building_status: String = String::new();
260 let elevator_space: String = String::from(" \t ");
261 for (i, floor) in self.floors.iter().enumerate() {
262 let mut floor_roof: String = String::from("----\t||---\t||");
264 let mut floor_body: String = format!("{:.2}\t||{}\t||", floor.dest_prob, floor.get_num_people());
265
266 let mut last_elevator_on_floor: usize = 0_usize;
268 for (j, elevator) in self.elevators.iter().enumerate() {
269 if elevator.floor_on != i as usize {
270 continue;
271 }
272
273 let elevator_roof: String = format!("{}{}", str::repeat(&elevator_space, j - last_elevator_on_floor as usize), String::from("|-\t|"));
275 let elevator_body: String = format!("{}|{}\t|", str::repeat(&elevator_space, j - last_elevator_on_floor as usize), elevator.get_num_people());
276
277 floor_roof.push_str(&elevator_roof);
279 floor_body.push_str(&elevator_body);
280
281 last_elevator_on_floor = j + 1_usize;
283 }
284
285 building_status = [floor_roof, floor_body, building_status].join("\n");
287 }
288 let wait_time_str: String = format!("Average wait time:\t{:.2}", self.avg_wait_time);
290 let energy_str: String = format!("Average energy spent:\t{:.2}", self.avg_energy);
291 let tip_str: String = format!("Total tips collected:\t${:.2}", self.tot_tips);
292 building_status = [building_status, wait_time_str, energy_str, tip_str].join("\n");
293
294 f.write_str(&building_status)
296 }
297}
298
299impl Floors for Building {
301 fn are_people_waiting_on_floor(&self, floor_index: usize) -> bool {
304 self.floors.are_people_waiting_on_floor(floor_index)
305 }
306
307 fn get_nearest_wait_floor(&self, floor_on: usize) -> (usize, usize) {
311 self.floors.get_nearest_wait_floor(floor_on)
312 }
313
314 fn get_dest_probabilities(&self) -> Vec<f64> {
317 self.floors.get_dest_probabilities()
318 }
319
320 fn gen_people_leaving(&mut self, rng: &mut impl Rng) {
324 self.floors.gen_people_leaving(rng)
325 }
326
327 fn flush_first_floor(&mut self) -> Vec<Person> {
329 self.floors.flush_first_floor()
330 }
331
332 fn increment_wait_times(&mut self) {
335 self.elevators.increment_wait_times();
336 self.floors.increment_wait_times();
337 }
338
339 fn append_floor(&mut self) {
341 self.floors.append_floor();
342 }
343}