popdat/
activities.rs

1use rand::Rng;
2use rand_xorshift::XorShiftRng;
3
4use geom::{Duration, Time};
5
6use crate::{Activity, CensusPerson, Config, PersonType, Schedule};
7
8impl CensusPerson {
9    pub fn generate_schedule(&self, _config: &Config, rng: &mut XorShiftRng) -> Schedule {
10        // TODO How do we pick these categories based on census data?
11        let person_type = if rng.gen_bool(0.5) {
12            PersonType::Student
13        } else {
14            PersonType::Worker
15        };
16
17        // Fill out a list of activities and how long the person should do the activity before
18        // travelling to the next place.
19        let mut plan = Vec::new();
20        let start_time;
21
22        match person_type {
23            PersonType::Student => {
24                // I'm probably channeling a college student here...
25                start_time = rand_time(rng, hours(8), hours(11));
26                if rng.gen_bool(0.95) {
27                    plan.push((Activity::Breakfast, minutes(30)));
28                }
29                plan.push((Activity::School, rand_duration(rng, hours(3), hours(6))));
30                if rng.gen_bool(0.3) {
31                    plan.push((
32                        Activity::Lunch,
33                        rand_duration(rng, minutes(20), minutes(40)),
34                    ));
35                }
36                plan.push((Activity::School, rand_duration(rng, hours(2), hours(4))));
37                if rng.gen_bool(0.6) {
38                    plan.push((Activity::Entertainment, hours(2)));
39                } else {
40                    plan.push((Activity::Errands, rand_duration(rng, minutes(15), hours(1))));
41                }
42                // The last duration doesn't matter
43                plan.push((Activity::Home, hours(8)));
44            }
45            PersonType::Worker => {
46                start_time = rand_time(rng, hours(6), hours(9));
47                if rng.gen_bool(0.8) {
48                    plan.push((Activity::Breakfast, minutes(15)));
49                }
50                plan.push((Activity::Work, rand_duration(rng, hours(4), hours(5))));
51                plan.push((
52                    Activity::Lunch,
53                    rand_duration(rng, minutes(20), minutes(40)),
54                ));
55                plan.push((Activity::Work, hours(4)));
56                if rng.gen_bool(0.8) {
57                    plan.push((Activity::Errands, rand_duration(rng, minutes(15), hours(1))));
58                }
59                // The last duration doesn't matter
60                plan.push((Activity::Home, hours(8)));
61            }
62        }
63
64        let mut schedule = Vec::new();
65        let mut now = start_time;
66        for (activity, duration) in plan {
67            schedule.push((now, activity));
68            // TODO We have to add in commute time here, but at this stage in the pipeline, we have
69            // no idea...
70            now += rand_duration(rng, Duration::minutes(30), Duration::hours(1));
71            now += duration;
72        }
73        Schedule {
74            activities: schedule,
75        }
76    }
77}
78
79fn rand_duration(rng: &mut XorShiftRng, low: Duration, high: Duration) -> Duration {
80    assert!(high > low);
81    Duration::seconds(rng.gen_range(low.inner_seconds()..high.inner_seconds()))
82}
83
84fn rand_time(rng: &mut XorShiftRng, low: Duration, high: Duration) -> Time {
85    Time::START_OF_DAY + rand_duration(rng, low, high)
86}
87
88// TODO I thought we could just use geom::Duration::{hours, minutes};   but this doesn't work
89fn minutes(x: usize) -> Duration {
90    Duration::minutes(x)
91}
92fn hours(x: usize) -> Duration {
93    Duration::hours(x)
94}