1 use crate::{
2     CarID, DrivingGoal, OrigPersonID, ParkingSpot, PersonID, SidewalkPOI, SidewalkSpot, Sim,
3     TripEndpoint, TripMode, TripSpec, Vehicle, VehicleSpec, VehicleType, BIKE_LENGTH,
4     MAX_CAR_LENGTH, MIN_CAR_LENGTH, SPAWN_DIST,
5 };
6 use abstutil::{prettyprint_usize, Counter, Timer};
7 use geom::{Distance, Duration, LonLat, Speed, Time};
8 use map_model::{
9     BuildingID, BusRouteID, BusStopID, DirectedRoadID, Map, OffstreetParking, PathConstraints,
10     Position, RoadID,
11 };
12 use rand::seq::SliceRandom;
13 use rand::{Rng, SeedableRng};
14 use rand_xorshift::XorShiftRng;
15 use serde::{Deserialize, Serialize};
16 use std::collections::{BTreeMap, BTreeSet, HashSet, VecDeque};
17 
18 // How to start a simulation.
19 #[derive(Clone, Serialize, Deserialize, Debug)]
20 pub struct Scenario {
21     pub scenario_name: String,
22     pub map_name: String,
23 
24     pub people: Vec<PersonSpec>,
25     // None means seed all buses. Otherwise the route name must be present here.
26     pub only_seed_buses: Option<BTreeSet<String>>,
27 }
28 
29 #[derive(Clone, Serialize, Deserialize, Debug)]
30 pub struct PersonSpec {
31     pub id: PersonID,
32     // Just used for debugging
33     pub orig_id: Option<OrigPersonID>,
34     pub trips: Vec<IndividTrip>,
35 }
36 
37 #[derive(Clone, Serialize, Deserialize, Debug)]
38 pub struct IndividTrip {
39     pub depart: Time,
40     pub trip: SpawnTrip,
41     pub cancelled: bool,
42     // Did a ScenarioModifier affect this?
43     pub modified: bool,
44 }
45 
46 impl IndividTrip {
new(depart: Time, trip: SpawnTrip) -> IndividTrip47     pub fn new(depart: Time, trip: SpawnTrip) -> IndividTrip {
48         IndividTrip {
49             depart,
50             trip,
51             cancelled: false,
52             modified: false,
53         }
54     }
55 }
56 
57 #[derive(Clone, Debug, Serialize, Deserialize)]
58 pub enum SpawnTrip {
59     // Only for interactive / debug trips
60     VehicleAppearing {
61         start: Position,
62         goal: DrivingGoal,
63         is_bike: bool,
64     },
65     FromBorder {
66         dr: DirectedRoadID,
67         goal: DrivingGoal,
68         // For bikes starting at a border, use FromBorder. UsingBike implies a walk->bike trip.
69         is_bike: bool,
70         origin: Option<OffMapLocation>,
71     },
72     UsingParkedCar(BuildingID, DrivingGoal),
73     UsingBike(BuildingID, DrivingGoal),
74     JustWalking(SidewalkSpot, SidewalkSpot),
75     UsingTransit(
76         SidewalkSpot,
77         SidewalkSpot,
78         BusRouteID,
79         BusStopID,
80         Option<BusStopID>,
81     ),
82     // Completely off-map trip. Don't really simulate much of it.
83     Remote {
84         from: OffMapLocation,
85         to: OffMapLocation,
86         trip_time: Duration,
87         mode: TripMode,
88     },
89 }
90 
91 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
92 pub struct OffMapLocation {
93     pub parcel_id: usize,
94     pub gps: LonLat,
95 }
96 
97 impl Scenario {
98     // Any case where map edits could change the calls to the RNG, we have to fork.
instantiate(&self, sim: &mut Sim, map: &Map, rng: &mut XorShiftRng, timer: &mut Timer)99     pub fn instantiate(&self, sim: &mut Sim, map: &Map, rng: &mut XorShiftRng, timer: &mut Timer) {
100         sim.set_name(self.scenario_name.clone());
101 
102         timer.start(format!("Instantiating {}", self.scenario_name));
103 
104         if let Some(ref routes) = self.only_seed_buses {
105             for route in map.all_bus_routes() {
106                 if routes.contains(&route.full_name) {
107                     sim.seed_bus_route(route);
108                 }
109             }
110         } else {
111             // All of them
112             for route in map.all_bus_routes() {
113                 sim.seed_bus_route(route);
114             }
115         }
116 
117         timer.start_iter("trips for People", self.people.len());
118         let mut spawner = sim.make_spawner();
119         let mut parked_cars: Vec<(Vehicle, BuildingID)> = Vec::new();
120         for p in &self.people {
121             timer.next();
122 
123             if let Err(err) = p.check_schedule(map) {
124                 panic!("{}", err);
125             }
126 
127             let (vehicle_specs, cars_initially_parked_at, vehicle_foreach_trip) =
128                 p.get_vehicles(rng);
129             sim.new_person(
130                 p.id,
131                 p.orig_id,
132                 Scenario::rand_ped_speed(rng),
133                 vehicle_specs,
134             );
135             let person = sim.get_person(p.id);
136             for (idx, b) in cars_initially_parked_at {
137                 parked_cars.push((person.vehicles[idx].clone(), b));
138             }
139             for (t, maybe_idx) in p.trips.iter().zip(vehicle_foreach_trip) {
140                 // The RNG call might change over edits for picking the spawning lane from a border
141                 // with multiple choices for a vehicle type.
142                 let mut tmp_rng = abstutil::fork_rng(rng);
143                 let spec = t.trip.clone().to_trip_spec(
144                     maybe_idx.map(|idx| person.vehicles[idx].id),
145                     &mut tmp_rng,
146                     map,
147                 );
148                 spawner.schedule_trip(
149                     person,
150                     t.depart,
151                     spec,
152                     t.trip.start(map),
153                     t.cancelled,
154                     t.modified,
155                     map,
156                 );
157             }
158         }
159 
160         // parked_cars is stable over map edits, so don't fork.
161         parked_cars.shuffle(rng);
162         seed_parked_cars(parked_cars, sim, map, rng, timer);
163 
164         sim.flush_spawner(spawner, map, timer);
165         timer.stop(format!("Instantiating {}", self.scenario_name));
166     }
167 
save(&self)168     pub fn save(&self) {
169         abstutil::write_binary(
170             abstutil::path_scenario(&self.map_name, &self.scenario_name),
171             self,
172         );
173     }
174 
empty(map: &Map, name: &str) -> Scenario175     pub fn empty(map: &Map, name: &str) -> Scenario {
176         Scenario {
177             scenario_name: name.to_string(),
178             map_name: map.get_name().to_string(),
179             people: Vec::new(),
180             only_seed_buses: Some(BTreeSet::new()),
181         }
182     }
183 
rand_car(rng: &mut XorShiftRng) -> VehicleSpec184     pub fn rand_car(rng: &mut XorShiftRng) -> VehicleSpec {
185         let length = Scenario::rand_dist(rng, MIN_CAR_LENGTH, MAX_CAR_LENGTH);
186         VehicleSpec {
187             vehicle_type: VehicleType::Car,
188             length,
189             max_speed: None,
190         }
191     }
192 
rand_bike(rng: &mut XorShiftRng) -> VehicleSpec193     pub fn rand_bike(rng: &mut XorShiftRng) -> VehicleSpec {
194         let max_speed = Some(Scenario::rand_speed(
195             rng,
196             Speed::miles_per_hour(8.0),
197             Speed::miles_per_hour(10.0),
198         ));
199         VehicleSpec {
200             vehicle_type: VehicleType::Bike,
201             length: BIKE_LENGTH,
202             max_speed,
203         }
204     }
205 
rand_dist(rng: &mut XorShiftRng, low: Distance, high: Distance) -> Distance206     pub fn rand_dist(rng: &mut XorShiftRng, low: Distance, high: Distance) -> Distance {
207         assert!(high > low);
208         Distance::meters(rng.gen_range(low.inner_meters(), high.inner_meters()))
209     }
210 
rand_speed(rng: &mut XorShiftRng, low: Speed, high: Speed) -> Speed211     fn rand_speed(rng: &mut XorShiftRng, low: Speed, high: Speed) -> Speed {
212         assert!(high > low);
213         Speed::meters_per_second(rng.gen_range(
214             low.inner_meters_per_second(),
215             high.inner_meters_per_second(),
216         ))
217     }
218 
rand_ped_speed(rng: &mut XorShiftRng) -> Speed219     pub fn rand_ped_speed(rng: &mut XorShiftRng) -> Speed {
220         Scenario::rand_speed(rng, Speed::miles_per_hour(2.0), Speed::miles_per_hour(3.0))
221     }
222 
count_parked_cars_per_bldg(&self) -> Counter<BuildingID>223     pub fn count_parked_cars_per_bldg(&self) -> Counter<BuildingID> {
224         let mut per_bldg = Counter::new();
225         // Pass in a dummy RNG
226         let mut rng = XorShiftRng::from_seed([0; 16]);
227         for p in &self.people {
228             let (_, cars_initially_parked_at, _) = p.get_vehicles(&mut rng);
229             for (_, b) in cars_initially_parked_at {
230                 per_bldg.inc(b);
231             }
232         }
233         per_bldg
234     }
235 
remove_weird_schedules(mut self, map: &Map) -> Scenario236     pub fn remove_weird_schedules(mut self, map: &Map) -> Scenario {
237         let orig = self.people.len();
238         self.people
239             .retain(|person| match person.check_schedule(map) {
240                 Ok(()) => true,
241                 Err(err) => {
242                     println!("{}", err);
243                     false
244                 }
245             });
246         println!(
247             "{} of {} people have nonsense schedules",
248             prettyprint_usize(orig - self.people.len()),
249             prettyprint_usize(orig)
250         );
251         // Fix up IDs
252         for (idx, person) in self.people.iter_mut().enumerate() {
253             person.id = PersonID(idx);
254         }
255         self
256     }
257 }
258 
seed_parked_cars( parked_cars: Vec<(Vehicle, BuildingID)>, sim: &mut Sim, map: &Map, base_rng: &mut XorShiftRng, timer: &mut Timer, )259 fn seed_parked_cars(
260     parked_cars: Vec<(Vehicle, BuildingID)>,
261     sim: &mut Sim,
262     map: &Map,
263     base_rng: &mut XorShiftRng,
264     timer: &mut Timer,
265 ) {
266     let mut open_spots_per_road: BTreeMap<RoadID, Vec<(ParkingSpot, Option<BuildingID>)>> =
267         BTreeMap::new();
268     for spot in sim.get_all_parking_spots().1 {
269         let (r, restriction) = match spot {
270             ParkingSpot::Onstreet(l, _) => (map.get_l(l).parent, None),
271             ParkingSpot::Offstreet(b, _) => (
272                 map.get_l(map.get_b(b).sidewalk()).parent,
273                 match map.get_b(b).parking {
274                     OffstreetParking::PublicGarage(_, _) => None,
275                     OffstreetParking::Private(_, _) => Some(b),
276                 },
277             ),
278             ParkingSpot::Lot(pl, _) => (map.get_l(map.get_pl(pl).driving_pos.lane()).parent, None),
279         };
280         open_spots_per_road
281             .entry(r)
282             .or_insert_with(Vec::new)
283             .push((spot, restriction));
284     }
285     // Changing parking on one road shouldn't affect far-off roads. Fork carefully.
286     for r in map.all_roads() {
287         let mut tmp_rng = abstutil::fork_rng(base_rng);
288         if let Some(ref mut spots) = open_spots_per_road.get_mut(&r.id) {
289             spots.shuffle(&mut tmp_rng);
290         }
291     }
292 
293     timer.start_iter("seed parked cars", parked_cars.len());
294     let mut ok = true;
295     let total_cars = parked_cars.len();
296     let mut seeded = 0;
297     for (vehicle, b) in parked_cars {
298         timer.next();
299         if !ok {
300             continue;
301         }
302         if let Some(spot) = find_spot_near_building(b, &mut open_spots_per_road, map) {
303             seeded += 1;
304             sim.seed_parked_car(vehicle, spot);
305         } else {
306             timer.warn(format!(
307                 "Not enough room to seed parked cars. Only found spots for {} of {}",
308                 prettyprint_usize(seeded),
309                 prettyprint_usize(total_cars)
310             ));
311             ok = false;
312         }
313     }
314 }
315 
316 // Pick a parking spot for this building. If the building's road has a free spot, use it. If not,
317 // start BFSing out from the road in a deterministic way until finding a nearby road with an open
318 // spot.
find_spot_near_building( b: BuildingID, open_spots_per_road: &mut BTreeMap<RoadID, Vec<(ParkingSpot, Option<BuildingID>)>>, map: &Map, ) -> Option<ParkingSpot>319 fn find_spot_near_building(
320     b: BuildingID,
321     open_spots_per_road: &mut BTreeMap<RoadID, Vec<(ParkingSpot, Option<BuildingID>)>>,
322     map: &Map,
323 ) -> Option<ParkingSpot> {
324     let mut roads_queue: VecDeque<RoadID> = VecDeque::new();
325     let mut visited: HashSet<RoadID> = HashSet::new();
326     {
327         let start = map.building_to_road(b).id;
328         roads_queue.push_back(start);
329         visited.insert(start);
330     }
331 
332     loop {
333         let r = roads_queue.pop_front()?;
334         if let Some(spots) = open_spots_per_road.get_mut(&r) {
335             // Fill in all private parking first before
336             // TODO With some probability, skip this available spot and park farther away
337             if let Some(idx) = spots
338                 .iter()
339                 .position(|(_, restriction)| restriction == &Some(b))
340             {
341                 return Some(spots.remove(idx).0);
342             }
343             if let Some(idx) = spots
344                 .iter()
345                 .position(|(_, restriction)| restriction.is_none())
346             {
347                 return Some(spots.remove(idx).0);
348             }
349         }
350 
351         for next_r in map.get_next_roads(r).into_iter() {
352             if !visited.contains(&next_r) {
353                 roads_queue.push_back(next_r);
354                 visited.insert(next_r);
355             }
356         }
357     }
358 }
359 
360 impl SpawnTrip {
to_trip_spec( self, use_vehicle: Option<CarID>, rng: &mut XorShiftRng, map: &Map, ) -> TripSpec361     fn to_trip_spec(
362         self,
363         use_vehicle: Option<CarID>,
364         rng: &mut XorShiftRng,
365         map: &Map,
366     ) -> TripSpec {
367         match self {
368             SpawnTrip::VehicleAppearing { start, goal, .. } => TripSpec::VehicleAppearing {
369                 start_pos: start,
370                 goal,
371                 use_vehicle: use_vehicle.unwrap(),
372                 retry_if_no_room: true,
373                 origin: None,
374             },
375             SpawnTrip::FromBorder {
376                 dr,
377                 goal,
378                 is_bike,
379                 origin,
380             } => {
381                 let constraints = if is_bike {
382                     PathConstraints::Bike
383                 } else {
384                     PathConstraints::Car
385                 };
386                 if let Some(l) = dr.lanes(constraints, map).choose(rng) {
387                     TripSpec::VehicleAppearing {
388                         start_pos: Position::new(*l, SPAWN_DIST),
389                         goal,
390                         use_vehicle: use_vehicle.unwrap(),
391                         retry_if_no_room: true,
392                         origin,
393                     }
394                 } else {
395                     TripSpec::NoRoomToSpawn {
396                         i: dr.src_i(map),
397                         goal,
398                         use_vehicle: use_vehicle.unwrap(),
399                         origin,
400                         error: format!("{} has no lanes to spawn a {:?}", dr.id, constraints),
401                     }
402                 }
403             }
404             SpawnTrip::UsingParkedCar(start_bldg, goal) => TripSpec::UsingParkedCar {
405                 start_bldg,
406                 goal,
407                 car: use_vehicle.unwrap(),
408             },
409             SpawnTrip::UsingBike(start, goal) => TripSpec::UsingBike {
410                 bike: use_vehicle.unwrap(),
411                 start,
412                 goal,
413             },
414             SpawnTrip::JustWalking(start, goal) => TripSpec::JustWalking { start, goal },
415             SpawnTrip::UsingTransit(start, goal, route, stop1, maybe_stop2) => {
416                 TripSpec::UsingTransit {
417                     start,
418                     goal,
419                     route,
420                     stop1,
421                     maybe_stop2,
422                 }
423             }
424             SpawnTrip::Remote {
425                 from,
426                 to,
427                 trip_time,
428                 mode,
429             } => TripSpec::Remote {
430                 from,
431                 to,
432                 trip_time,
433                 mode,
434             },
435         }
436     }
437 
438     // TODO Why do I feel like this code is sitting somewhere else already
mode(&self) -> TripMode439     pub fn mode(&self) -> TripMode {
440         match self {
441             SpawnTrip::VehicleAppearing { is_bike, .. } => {
442                 if *is_bike {
443                     TripMode::Bike
444                 } else {
445                     TripMode::Drive
446                 }
447             }
448             SpawnTrip::FromBorder { is_bike, .. } => {
449                 if *is_bike {
450                     TripMode::Bike
451                 } else {
452                     TripMode::Drive
453                 }
454             }
455             SpawnTrip::UsingParkedCar(_, _) => TripMode::Drive,
456             SpawnTrip::UsingBike(_, _) => TripMode::Bike,
457             SpawnTrip::JustWalking(_, _) => TripMode::Walk,
458             SpawnTrip::UsingTransit(_, _, _, _, _) => TripMode::Transit,
459             // TODO Uh...
460             SpawnTrip::Remote { .. } => TripMode::Drive,
461         }
462     }
463 
start(&self, map: &Map) -> TripEndpoint464     pub fn start(&self, map: &Map) -> TripEndpoint {
465         match self {
466             SpawnTrip::VehicleAppearing { ref start, .. } => {
467                 TripEndpoint::Border(map.get_l(start.lane()).src_i, None)
468             }
469             SpawnTrip::FromBorder { dr, ref origin, .. } => {
470                 TripEndpoint::Border(dr.src_i(map), origin.clone())
471             }
472             SpawnTrip::UsingParkedCar(b, _) => TripEndpoint::Bldg(*b),
473             SpawnTrip::UsingBike(b, _) => TripEndpoint::Bldg(*b),
474             SpawnTrip::JustWalking(ref spot, _) | SpawnTrip::UsingTransit(ref spot, _, _, _, _) => {
475                 match spot.connection {
476                     SidewalkPOI::Building(b) => TripEndpoint::Bldg(b),
477                     SidewalkPOI::Border(i, ref loc) => TripEndpoint::Border(i, loc.clone()),
478                     SidewalkPOI::SuddenlyAppear => {
479                         TripEndpoint::Border(map.get_l(spot.sidewalk_pos.lane()).src_i, None)
480                     }
481                     _ => unreachable!(),
482                 }
483             }
484             // Pick an arbitrary border
485             SpawnTrip::Remote { ref from, .. } => {
486                 TripEndpoint::Border(map.all_outgoing_borders()[0].id, Some(from.clone()))
487             }
488         }
489     }
490 
end(&self, map: &Map) -> TripEndpoint491     pub fn end(&self, map: &Map) -> TripEndpoint {
492         match self {
493             SpawnTrip::VehicleAppearing { ref goal, .. }
494             | SpawnTrip::FromBorder { ref goal, .. }
495             | SpawnTrip::UsingParkedCar(_, ref goal)
496             | SpawnTrip::UsingBike(_, ref goal) => match goal {
497                 DrivingGoal::ParkNear(b) => TripEndpoint::Bldg(*b),
498                 DrivingGoal::Border(i, _, ref loc) => TripEndpoint::Border(*i, loc.clone()),
499             },
500             SpawnTrip::JustWalking(_, ref spot) | SpawnTrip::UsingTransit(_, ref spot, _, _, _) => {
501                 match spot.connection {
502                     SidewalkPOI::Building(b) => TripEndpoint::Bldg(b),
503                     SidewalkPOI::Border(i, ref loc) => TripEndpoint::Border(i, loc.clone()),
504                     _ => unreachable!(),
505                 }
506             }
507             // Pick an arbitrary border
508             SpawnTrip::Remote { ref to, .. } => {
509                 TripEndpoint::Border(map.all_incoming_borders()[0].id, Some(to.clone()))
510             }
511         }
512     }
513 
new( from: TripEndpoint, to: TripEndpoint, mode: TripMode, map: &Map, ) -> Option<SpawnTrip>514     pub fn new(
515         from: TripEndpoint,
516         to: TripEndpoint,
517         mode: TripMode,
518         map: &Map,
519     ) -> Option<SpawnTrip> {
520         Some(match mode {
521             TripMode::Drive => match from {
522                 TripEndpoint::Bldg(b) => {
523                     SpawnTrip::UsingParkedCar(b, to.driving_goal(PathConstraints::Car, map)?)
524                 }
525                 TripEndpoint::Border(i, ref origin) => SpawnTrip::FromBorder {
526                     dr: map.get_i(i).some_outgoing_road(map)?,
527                     goal: to.driving_goal(PathConstraints::Car, map)?,
528                     is_bike: false,
529                     origin: origin.clone(),
530                 },
531             },
532             TripMode::Bike => match from {
533                 TripEndpoint::Bldg(b) => {
534                     SpawnTrip::UsingBike(b, to.driving_goal(PathConstraints::Bike, map)?)
535                 }
536                 TripEndpoint::Border(i, ref origin) => SpawnTrip::FromBorder {
537                     dr: map.get_i(i).some_outgoing_road(map)?,
538                     goal: to.driving_goal(PathConstraints::Bike, map)?,
539                     is_bike: true,
540                     origin: origin.clone(),
541                 },
542             },
543             TripMode::Walk => {
544                 SpawnTrip::JustWalking(from.start_sidewalk_spot(map)?, to.end_sidewalk_spot(map)?)
545             }
546             TripMode::Transit => {
547                 let start = from.start_sidewalk_spot(map)?;
548                 let goal = to.end_sidewalk_spot(map)?;
549                 if let Some((stop1, maybe_stop2, route)) =
550                     map.should_use_transit(start.sidewalk_pos, goal.sidewalk_pos)
551                 {
552                     SpawnTrip::UsingTransit(start, goal, route, stop1, maybe_stop2)
553                 } else {
554                     //timer.warn(format!("{:?} not actually using transit, because pathfinding
555                     // didn't find any useful route", trip));
556                     SpawnTrip::JustWalking(start, goal)
557                 }
558             }
559         })
560     }
561 }
562 
563 impl PersonSpec {
564     // Verify that the trip start/endpoints of the person match up
check_schedule(&self, map: &Map) -> Result<(), String>565     fn check_schedule(&self, map: &Map) -> Result<(), String> {
566         for pair in self.trips.iter().zip(self.trips.iter().skip(1)) {
567             if pair.0.depart >= pair.1.depart {
568                 return Err(format!(
569                     "{} {:?} starts two trips in the wrong order: {} then {}",
570                     self.id, self.orig_id, pair.0.depart, pair.1.depart
571                 ));
572             }
573 
574             // Once off-map, re-enter via any border node.
575             let end_bldg = match pair.0.trip.end(map) {
576                 TripEndpoint::Bldg(b) => Some(b),
577                 TripEndpoint::Border(_, _) => None,
578             };
579             let start_bldg = match pair.1.trip.start(map) {
580                 TripEndpoint::Bldg(b) => Some(b),
581                 TripEndpoint::Border(_, _) => None,
582             };
583 
584             if end_bldg != start_bldg {
585                 return Err(format!(
586                     "At {}, {} {:?} warps between some trips, from {:?} to {:?}",
587                     pair.1.depart, self.id, self.orig_id, end_bldg, start_bldg
588                 ));
589             }
590 
591             // But actually, make sure pairs of remote trips match up.
592             if let (SpawnTrip::Remote { ref to, .. }, SpawnTrip::Remote { ref from, .. }) =
593                 (&pair.0.trip, &pair.1.trip)
594             {
595                 if to != from {
596                     return Err(format!(
597                         "At {}, {} {:?} warps between some trips, from {:?} to {:?}",
598                         pair.1.depart, self.id, self.orig_id, to, from
599                     ));
600                 }
601             }
602         }
603         Ok(())
604     }
605 
get_vehicles( &self, rng: &mut XorShiftRng, ) -> ( Vec<VehicleSpec>, Vec<(usize, BuildingID)>, Vec<Option<usize>>, )606     fn get_vehicles(
607         &self,
608         rng: &mut XorShiftRng,
609     ) -> (
610         Vec<VehicleSpec>,
611         Vec<(usize, BuildingID)>,
612         Vec<Option<usize>>,
613     ) {
614         let mut vehicle_specs = Vec::new();
615         let mut cars_initially_parked_at = Vec::new();
616         let mut vehicle_foreach_trip = Vec::new();
617 
618         let mut bike_idx = None;
619         // For each indexed car, is it parked somewhere, or off-map?
620         let mut car_locations: Vec<(usize, Option<BuildingID>)> = Vec::new();
621 
622         // TODO If the trip is cancelled, this should be affected...
623         for trip in &self.trips {
624             let use_for_trip = match trip.trip {
625                 SpawnTrip::VehicleAppearing {
626                     is_bike, ref goal, ..
627                 }
628                 | SpawnTrip::FromBorder {
629                     is_bike, ref goal, ..
630                 } => {
631                     if is_bike {
632                         if bike_idx.is_none() {
633                             bike_idx = Some(vehicle_specs.len());
634                             vehicle_specs.push(Scenario::rand_bike(rng));
635                         }
636                         bike_idx
637                     } else {
638                         // Any available cars off-map?
639                         let idx = if let Some(idx) = car_locations
640                             .iter()
641                             .find(|(_, parked_at)| parked_at.is_none())
642                             .map(|(idx, _)| *idx)
643                         {
644                             idx
645                         } else {
646                             // Need a new car, starting off-map
647                             let idx = vehicle_specs.len();
648                             vehicle_specs.push(Scenario::rand_car(rng));
649                             idx
650                         };
651 
652                         // Where does this car wind up?
653                         car_locations.retain(|(i, _)| idx != *i);
654                         match goal {
655                             DrivingGoal::ParkNear(b) => {
656                                 car_locations.push((idx, Some(*b)));
657                             }
658                             DrivingGoal::Border(_, _, _) => {
659                                 car_locations.push((idx, None));
660                             }
661                         }
662 
663                         Some(idx)
664                     }
665                 }
666                 SpawnTrip::UsingParkedCar(b, ref goal) => {
667                     // Is there already a car parked here?
668                     let idx = if let Some(idx) = car_locations
669                         .iter()
670                         .find(|(_, parked_at)| *parked_at == Some(b))
671                         .map(|(idx, _)| *idx)
672                     {
673                         idx
674                     } else {
675                         // Need a new car, starting at this building
676                         let idx = vehicle_specs.len();
677                         vehicle_specs.push(Scenario::rand_car(rng));
678                         cars_initially_parked_at.push((idx, b));
679                         idx
680                     };
681 
682                     // Where does this car wind up?
683                     car_locations.retain(|(i, _)| idx != *i);
684                     match goal {
685                         DrivingGoal::ParkNear(b) => {
686                             car_locations.push((idx, Some(*b)));
687                         }
688                         DrivingGoal::Border(_, _, _) => {
689                             car_locations.push((idx, None));
690                         }
691                     }
692 
693                     Some(idx)
694                 }
695                 SpawnTrip::UsingBike(_, _) => {
696                     if bike_idx.is_none() {
697                         bike_idx = Some(vehicle_specs.len());
698                         vehicle_specs.push(Scenario::rand_bike(rng));
699                     }
700                     bike_idx
701                 }
702                 SpawnTrip::JustWalking(_, _) | SpawnTrip::UsingTransit(_, _, _, _, _) => None,
703                 SpawnTrip::Remote { .. } => None,
704             };
705             vehicle_foreach_trip.push(use_for_trip);
706         }
707 
708         // For debugging
709         if false {
710             let mut n = vehicle_specs.len();
711             if bike_idx.is_some() {
712                 n -= 1;
713             }
714             if n > 1 {
715                 println!("{} needs {} cars", self.id, n);
716             }
717         }
718 
719         (
720             vehicle_specs,
721             cars_initially_parked_at,
722             vehicle_foreach_trip,
723         )
724     }
725 }
726