1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
use crate::{CarID, VehicleType};
use geom::{Duration, Time};
use map_model::{LaneID, Map, Path, PathConstraints, PathRequest, PathStep};
use serde::{Deserialize, Serialize};
use std::collections::{BTreeMap, BTreeSet};
type ZoneIdx = usize;
#[derive(Serialize, Deserialize, Clone)]
pub struct CapSimState {
lane_to_zone: BTreeMap<LaneID, ZoneIdx>,
zones: Vec<Zone>,
}
#[derive(Serialize, Deserialize, Clone)]
struct Zone {
cap: usize,
entered_in_last_hour: BTreeSet<CarID>,
hour_started: Time,
}
impl CapSimState {
pub fn new(map: &Map) -> CapSimState {
let mut sim = CapSimState {
lane_to_zone: BTreeMap::new(),
zones: Vec::new(),
};
for z in map.all_zones() {
if let Some(cap) = z.restrictions.cap_vehicles_per_hour {
let idx = sim.zones.len();
for r in &z.members {
for l in map.get_r(*r).all_lanes() {
if PathConstraints::Car.can_use(map.get_l(l), map) {
sim.lane_to_zone.insert(l, idx);
}
}
}
sim.zones.push(Zone {
cap,
entered_in_last_hour: BTreeSet::new(),
hour_started: Time::START_OF_DAY,
});
}
}
sim
}
fn allow_trip(&mut self, now: Time, car: CarID, path: &Path) -> bool {
if car.1 != VehicleType::Car {
return true;
}
for step in path.get_steps() {
if let PathStep::Lane(l) = step {
if let Some(idx) = self.lane_to_zone.get(l) {
let zone = &mut self.zones[*idx];
if now - zone.hour_started >= Duration::hours(1) {
zone.hour_started = Time::START_OF_DAY + Duration::hours(now.get_parts().0);
zone.entered_in_last_hour.clear();
}
if zone.entered_in_last_hour.len() >= zone.cap
&& !zone.entered_in_last_hour.contains(&car)
{
return false;
}
zone.entered_in_last_hour.insert(car);
}
}
}
true
}
pub fn validate_path(
&mut self,
req: &PathRequest,
path: Path,
now: Time,
car: CarID,
capped: &mut bool,
map: &Map,
) -> Option<Path> {
if self.allow_trip(now, car, &path) {
return Some(path);
}
*capped = true;
let mut avoid_lanes: BTreeSet<LaneID> = BTreeSet::new();
for (l, idx) in &self.lane_to_zone {
let zone = &self.zones[*idx];
if zone.entered_in_last_hour.len() >= zone.cap
&& !zone.entered_in_last_hour.contains(&car)
{
avoid_lanes.insert(*l);
}
}
map.pathfind_avoiding_zones(req.clone(), avoid_lanes)
}
pub fn get_cap_counter(&self, l: LaneID) -> usize {
if let Some(idx) = self.lane_to_zone.get(&l) {
self.zones[*idx].entered_in_last_hour.len()
} else {
0
}
}
}