mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-29 04:35:51 +03:00
moving state to transit model, making router get directives from it
This commit is contained in:
parent
da402dd2c1
commit
c685a80a98
@ -652,13 +652,32 @@ for now, since pathfinding ignores live traffic, probably fine to ignore this.
|
|||||||
- this actually belongs to the map layer! associated with a sidewalk I guess.
|
- this actually belongs to the map layer! associated with a sidewalk I guess.
|
||||||
- render the bus in a special color, and also, make it really long (adjust following dist, but not parking spot len)
|
- render the bus in a special color, and also, make it really long (adjust following dist, but not parking spot len)
|
||||||
- how to unit test that a bus has reached a stop and is waiting? how do we even know that a bus is at a stop for peds to soon board it? I think a transit state will happen soon...
|
- how to unit test that a bus has reached a stop and is waiting? how do we even know that a bus is at a stop for peds to soon board it? I think a transit state will happen soon...
|
||||||
|
|
||||||
- step 2: make some peds pick a SINGLE bus to use for their route, if it helps
|
- step 2: make some peds pick a SINGLE bus to use for their route, if it helps
|
||||||
|
|
||||||
- step 3: make peds load on the bus and get off at the correct stop. make buses usually wait a fixed time at each stop, but wait a littl extra if loading passengers takes a while.
|
- step 3: make peds load on the bus and get off at the correct stop. make buses usually wait a fixed time at each stop, but wait a littl extra if loading passengers takes a while.
|
||||||
- will need to store transit state of what peds are on what bus somewhere... right? or can trips somehow do it? but will want to jump to a ped and spot the bus
|
- should walking state own peds waiting for a bus?
|
||||||
|
- yes: easier drawing, later need to know how crowded a sidewalk is, it's just weird to keep indicating we're at a place. router for cars does this, and the transit sim holds the higher-level state. do the same for now.
|
||||||
|
- no: transit sim can also contribute DrawPeds. the walking layer has nothing left to do with them... right?
|
||||||
|
|
||||||
- step N: load in GTFS for seattle to get real routes and stops
|
- step N: load in GTFS for seattle to get real routes and stops
|
||||||
|
|
||||||
later: multiple transfers, dedicated bus lanes, light rail...
|
later: multiple transfers, dedicated bus lanes, light rail...
|
||||||
|
|
||||||
|
Actually, jump to step 3 and just hardcode a ped to use a route, for now. what should the setup be? hardcode what stop to go to, what route to use, what stop to get off at? trip plan is a sequence...
|
||||||
|
|
||||||
|
- walk to a sidewalk POI (bldg, parking spot, bus stop)
|
||||||
|
- drive somewhere and park
|
||||||
|
- ride bus route until some stop
|
||||||
|
|
||||||
|
for now, these trip sequences can be hardcoded, and planned later.
|
||||||
|
|
||||||
|
## Everything as FSMs
|
||||||
|
|
||||||
|
Driving and walking layer are both kind of broken, since they know about
|
||||||
|
parking spots and bus stops. Feels like they need to be dumb, mechanical layers
|
||||||
|
that're guided by higher-level behaviors, which understand trips and such.
|
||||||
|
|
||||||
## Routers, lookahead, cars as FSMs
|
## Routers, lookahead, cars as FSMs
|
||||||
|
|
||||||
Hmm, hard to figure out the interactions for the router. when should it get a
|
Hmm, hard to figure out the interactions for the router. when should it get a
|
||||||
|
@ -175,6 +175,7 @@ impl Car {
|
|||||||
vehicle,
|
vehicle,
|
||||||
map,
|
map,
|
||||||
parking_sim,
|
parking_sim,
|
||||||
|
transit_sim,
|
||||||
);
|
);
|
||||||
let dist_to_maybe_stop_at = maybe_stop_early.unwrap_or(current_on.length(map));
|
let dist_to_maybe_stop_at = maybe_stop_early.unwrap_or(current_on.length(map));
|
||||||
let dist_from_stop = dist_to_maybe_stop_at - current_dist_along;
|
let dist_from_stop = dist_to_maybe_stop_at - current_dist_along;
|
||||||
|
@ -36,13 +36,16 @@ pub fn small_spawn(sim: &mut Sim, map: &Map) {
|
|||||||
sim.seed_walking_trips(&map, 100);
|
sim.seed_walking_trips(&map, 100);
|
||||||
sim.seed_driving_trips(&map, 100);
|
sim.seed_driving_trips(&map, 100);
|
||||||
|
|
||||||
sim.seed_bus(
|
if sim.seed_bus_route(
|
||||||
vec![
|
vec![
|
||||||
map.get_l(LaneID(309)).bus_stops[0].clone(),
|
map.get_l(LaneID(309)).bus_stops[0].clone(),
|
||||||
map.get_l(LaneID(840)).bus_stops[0].clone(),
|
map.get_l(LaneID(840)).bus_stops[0].clone(),
|
||||||
],
|
],
|
||||||
map,
|
map,
|
||||||
).expect("Bus didn't fit");
|
).len() != 2
|
||||||
|
{
|
||||||
|
panic!("Two buses didn't fit");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn big_spawn(sim: &mut Sim, map: &Map) {
|
pub fn big_spawn(sim: &mut Sim, map: &Map) {
|
||||||
|
@ -62,6 +62,15 @@ impl fmt::Display for PedestrianID {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
|
pub struct RouteID(pub usize);
|
||||||
|
|
||||||
|
impl fmt::Display for RouteID {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "RouteID({0})", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug, Hash)]
|
#[derive(Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug, Hash)]
|
||||||
pub enum AgentID {
|
pub enum AgentID {
|
||||||
Car(CarID),
|
Car(CarID),
|
||||||
|
@ -2,8 +2,7 @@ use dimensioned::si;
|
|||||||
use driving::{Action, CarView};
|
use driving::{Action, CarView};
|
||||||
use kinematics;
|
use kinematics;
|
||||||
use kinematics::Vehicle;
|
use kinematics::Vehicle;
|
||||||
use map_model;
|
use map_model::{BuildingID, LaneID, Map, TurnID};
|
||||||
use map_model::{BuildingID, BusStop, LaneID, Map, TurnID};
|
|
||||||
use parking::ParkingSimState;
|
use parking::ParkingSimState;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
@ -13,11 +12,7 @@ use {Distance, Event, On, ParkingSpot, Tick};
|
|||||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
enum Goal {
|
enum Goal {
|
||||||
ParkNearBuilding(BuildingID),
|
ParkNearBuilding(BuildingID),
|
||||||
// This is stateful -- first stop is the one we're aiming for now, and we might also be waiting
|
FollowBusRoute,
|
||||||
// at that stop for a little while.
|
|
||||||
// Buses really have a few states... GotoNextStop(list of stops), WaitAtStop(list of stops,
|
|
||||||
// tick)
|
|
||||||
CycleThroughStops(Vec<BusStop>, Option<Tick>),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gives higher-level instructions to a car.
|
// Gives higher-level instructions to a car.
|
||||||
@ -37,11 +32,10 @@ impl Router {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn make_router_for_bus(first_path: VecDeque<LaneID>, stops: Vec<BusStop>) -> Router {
|
pub fn make_router_for_bus(first_path: VecDeque<LaneID>) -> Router {
|
||||||
assert_eq!(*first_path.back().unwrap(), stops[1].driving_lane);
|
|
||||||
Router {
|
Router {
|
||||||
path: first_path,
|
path: first_path,
|
||||||
goal: Goal::CycleThroughStops(rotate_stops(&stops), None),
|
goal: Goal::FollowBusRoute,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,12 +58,14 @@ impl Router {
|
|||||||
transit_sim: &mut TransitSimState,
|
transit_sim: &mut TransitSimState,
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
) -> Option<Action> {
|
) -> Option<Action> {
|
||||||
if self.path.is_empty() && view.speed <= kinematics::EPSILON_SPEED {
|
if !self.path.is_empty() || view.speed > kinematics::EPSILON_SPEED {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
match self.goal {
|
match self.goal {
|
||||||
Goal::ParkNearBuilding(_) => {
|
Goal::ParkNearBuilding(_) => {
|
||||||
let last_lane = view.on.as_lane();
|
let last_lane = view.on.as_lane();
|
||||||
if let Some(spot) =
|
if let Some(spot) = find_parking_spot(last_lane, view.dist_along, map, parking_sim)
|
||||||
find_parking_spot(last_lane, view.dist_along, map, parking_sim)
|
|
||||||
{
|
{
|
||||||
if parking_sim.dist_along_for_car(spot, vehicle) == view.dist_along {
|
if parking_sim.dist_along_for_car(spot, vehicle) == view.dist_along {
|
||||||
return Some(Action::StartParking(spot));
|
return Some(Action::StartParking(spot));
|
||||||
@ -80,60 +76,17 @@ impl Router {
|
|||||||
return self.look_for_parking(last_lane, view, map, rng);
|
return self.look_for_parking(last_lane, view, map, rng);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Goal::CycleThroughStops(ref mut stops, ref mut wait_until) => {
|
Goal::FollowBusRoute => {
|
||||||
if view.dist_along == stops[0].dist_along {
|
let (should_idle, new_path) =
|
||||||
if let Some(wait) = wait_until.clone() {
|
transit_sim.get_action_when_stopped_at_end(events, view, time, map);
|
||||||
if time == wait {
|
if let Some(p) = new_path {
|
||||||
// TODO is this the right place to actually do the state
|
self.path = p;
|
||||||
// transition, or should we just indicate an event and let
|
|
||||||
// something else handle it?
|
|
||||||
events.push(Event::BusDepartedFromStop(view.id, stops[0].clone()));
|
|
||||||
|
|
||||||
if view.debug || true {
|
|
||||||
println!(
|
|
||||||
"{} finished waiting at bus stop, going to next stop {:?}",
|
|
||||||
view.id, stops[1]
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
if should_idle {
|
||||||
let mut new_path = VecDeque::from(
|
|
||||||
map_model::pathfind(
|
|
||||||
map,
|
|
||||||
stops[0].driving_lane,
|
|
||||||
stops[1].driving_lane,
|
|
||||||
).expect(&format!(
|
|
||||||
"No route between bus stops {:?} and {:?}",
|
|
||||||
stops[0], stops[1]
|
|
||||||
)),
|
|
||||||
);
|
|
||||||
new_path.pop_front();
|
|
||||||
self.path = new_path;
|
|
||||||
|
|
||||||
let new_stops = rotate_stops(stops);
|
|
||||||
stops.clear();
|
|
||||||
stops.extend(new_stops);
|
|
||||||
*wait_until = None;
|
|
||||||
|
|
||||||
transit_sim.bus_is_driving(view.id);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
assert_eq!(view.on.as_lane(), stops[0].driving_lane);
|
|
||||||
events.push(Event::BusArrivedAtStop(view.id, stops[0].clone()));
|
|
||||||
// TODO const
|
|
||||||
*wait_until = Some(time + 10.0 * si::S);
|
|
||||||
if view.debug || true {
|
|
||||||
println!(
|
|
||||||
"{} reached {:?}, now waiting until {:?}",
|
|
||||||
view.id, stops[0], wait_until
|
|
||||||
);
|
|
||||||
}
|
|
||||||
transit_sim.bus_is_at_stop(view.id, stops[0].clone());
|
|
||||||
return Some(Action::Continue(0.0 * si::MPS2, Vec::new()));
|
return Some(Action::Continue(0.0 * si::MPS2, Vec::new()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,6 +99,7 @@ impl Router {
|
|||||||
vehicle: &Vehicle,
|
vehicle: &Vehicle,
|
||||||
map: &Map,
|
map: &Map,
|
||||||
parking_sim: &ParkingSimState,
|
parking_sim: &ParkingSimState,
|
||||||
|
transit_sim: &TransitSimState,
|
||||||
) -> Option<Distance> {
|
) -> Option<Distance> {
|
||||||
if self.path.is_empty() {
|
if self.path.is_empty() {
|
||||||
match self.goal {
|
match self.goal {
|
||||||
@ -160,8 +114,8 @@ impl Router {
|
|||||||
return Some(on.length(map));
|
return Some(on.length(map));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Goal::CycleThroughStops(ref stops, _) => {
|
Goal::FollowBusRoute => {
|
||||||
return Some(stops[0].dist_along);
|
return Some(transit_sim.get_dist_to_stop_at(vehicle.id, on.as_lane()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -221,10 +175,3 @@ fn find_parking_spot(
|
|||||||
.find_parking_lane(driving_lane)
|
.find_parking_lane(driving_lane)
|
||||||
.and_then(|l| parking_sim.get_first_free_spot(l, dist_along))
|
.and_then(|l| parking_sim.get_first_free_spot(l, dist_along))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO double-ended list can do this natively
|
|
||||||
fn rotate_stops(stops: &Vec<BusStop>) -> Vec<BusStop> {
|
|
||||||
let mut cycled_stops: Vec<BusStop> = stops[1..].to_vec();
|
|
||||||
cycled_stops.push(stops[0].clone());
|
|
||||||
cycled_stops
|
|
||||||
}
|
|
||||||
|
@ -115,10 +115,11 @@ impl Sim {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn seed_bus(&mut self, stops: Vec<BusStop>, map: &Map) -> Option<CarID> {
|
pub fn seed_bus_route(&mut self, stops: Vec<BusStop>, map: &Map) -> Vec<CarID> {
|
||||||
// TODO throw away the events? :(
|
// TODO throw away the events? :(
|
||||||
let mut events: Vec<Event> = Vec::new();
|
let mut events: Vec<Event> = Vec::new();
|
||||||
if let Some(v) = self.spawner.seed_bus(
|
let mut result: Vec<CarID> = Vec::new();
|
||||||
|
for v in self.spawner.seed_bus_route(
|
||||||
&mut events,
|
&mut events,
|
||||||
stops,
|
stops,
|
||||||
&mut self.rng,
|
&mut self.rng,
|
||||||
@ -130,10 +131,9 @@ impl Sim {
|
|||||||
) {
|
) {
|
||||||
let id = v.id;
|
let id = v.id;
|
||||||
self.car_properties.insert(v.id, v);
|
self.car_properties.insert(v.id, v);
|
||||||
Some(id)
|
result.push(id);
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn seed_specific_parked_cars(&mut self, lane: LaneID, spots: Vec<usize>) -> Vec<CarID> {
|
pub fn seed_specific_parked_cars(&mut self, lane: LaneID, spots: Vec<usize>) -> Vec<CarID> {
|
||||||
|
@ -168,7 +168,7 @@ impl Spawner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This happens immediately; it isn't scheduled.
|
// This happens immediately; it isn't scheduled.
|
||||||
pub fn seed_bus<R: Rng + ?Sized>(
|
pub fn seed_bus_route<R: Rng + ?Sized>(
|
||||||
&mut self,
|
&mut self,
|
||||||
events: &mut Vec<Event>,
|
events: &mut Vec<Event>,
|
||||||
stops: Vec<BusStop>,
|
stops: Vec<BusStop>,
|
||||||
@ -178,38 +178,40 @@ impl Spawner {
|
|||||||
transit_sim: &mut TransitSimState,
|
transit_sim: &mut TransitSimState,
|
||||||
now: Tick,
|
now: Tick,
|
||||||
properties: &BTreeMap<CarID, Vehicle>,
|
properties: &BTreeMap<CarID, Vehicle>,
|
||||||
) -> Option<Vehicle> {
|
) -> Vec<Vehicle> {
|
||||||
assert!(stops.len() > 1);
|
let route = transit_sim.create_empty_route(stops);
|
||||||
|
let mut vehicles: Vec<Vehicle> = Vec::new();
|
||||||
|
// Try to spawn a bus at each stop
|
||||||
|
for (next_stop_idx, start_dist_along, mut path) in
|
||||||
|
transit_sim.get_route_starts(route, map).into_iter()
|
||||||
|
{
|
||||||
let id = CarID(self.car_id_counter);
|
let id = CarID(self.car_id_counter);
|
||||||
self.car_id_counter += 1;
|
self.car_id_counter += 1;
|
||||||
let vehicle = Vehicle::generate_bus(id, rng);
|
let vehicle = Vehicle::generate_bus(id, rng);
|
||||||
|
|
||||||
let mut first_path = VecDeque::from(
|
let start = path.pop_front().unwrap();
|
||||||
map_model::pathfind(map, stops[0].driving_lane, stops[1].driving_lane).expect(
|
|
||||||
&format!(
|
|
||||||
"No route between bus stops {:?} and {:?}",
|
|
||||||
stops[0], stops[1]
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
let start = first_path.pop_front().unwrap();
|
|
||||||
if driving_sim.start_car_on_lane(
|
if driving_sim.start_car_on_lane(
|
||||||
events,
|
events,
|
||||||
now,
|
now,
|
||||||
id,
|
id,
|
||||||
None,
|
None,
|
||||||
stops[0].dist_along,
|
start_dist_along,
|
||||||
start,
|
start,
|
||||||
Router::make_router_for_bus(first_path, stops),
|
Router::make_router_for_bus(path),
|
||||||
map,
|
map,
|
||||||
properties,
|
properties,
|
||||||
) {
|
) {
|
||||||
transit_sim.bus_is_driving(id);
|
transit_sim.bus_created(id, route, next_stop_idx);
|
||||||
println!("Spawned bus {}", id);
|
println!("Spawned bus {} for route {}", id, route);
|
||||||
return Some(vehicle);
|
vehicles.push(vehicle);
|
||||||
|
} else {
|
||||||
|
println!(
|
||||||
|
"No room for a bus headed towards stop {} of {}, giving up",
|
||||||
|
next_stop_idx, route
|
||||||
|
);
|
||||||
}
|
}
|
||||||
println!("No room for bus, giving up");
|
}
|
||||||
None
|
vehicles
|
||||||
}
|
}
|
||||||
|
|
||||||
// This happens immediately; it isn't scheduled.
|
// This happens immediately; it isn't scheduled.
|
||||||
|
@ -1,31 +1,181 @@
|
|||||||
use map_model::BusStop;
|
use dimensioned::si;
|
||||||
use std::collections::BTreeMap;
|
use driving::CarView;
|
||||||
use CarID;
|
use events::Event;
|
||||||
|
use map_model;
|
||||||
|
use map_model::{BusStop, LaneID, Map};
|
||||||
|
use std::collections::{BTreeMap, VecDeque};
|
||||||
|
use {CarID, Distance, PedestrianID, RouteID, Tick};
|
||||||
|
|
||||||
|
type StopIdx = usize;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
struct Route {
|
||||||
|
id: RouteID,
|
||||||
|
buses: Vec<CarID>,
|
||||||
|
stops: Vec<BusStop>,
|
||||||
|
// TODO info on schedules
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Route {
|
||||||
|
fn next_stop(&self, idx: StopIdx) -> StopIdx {
|
||||||
|
if idx + 1 == self.stops.len() {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
idx + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
struct Bus {
|
||||||
|
car: CarID,
|
||||||
|
route: RouteID,
|
||||||
|
passengers: Vec<PedestrianID>,
|
||||||
|
state: BusState,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Serialize, Deserialize, PartialEq, Eq)]
|
||||||
enum BusState {
|
enum BusState {
|
||||||
Driving,
|
DrivingToStop(StopIdx),
|
||||||
AtStop(BusStop),
|
// When do we leave?
|
||||||
|
AtStop(StopIdx, Tick),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Serialize, Deserialize, PartialEq, Eq)]
|
||||||
pub struct TransitSimState {
|
pub struct TransitSimState {
|
||||||
buses: BTreeMap<CarID, BusState>,
|
buses: BTreeMap<CarID, Bus>,
|
||||||
|
routes: BTreeMap<RouteID, Route>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TransitSimState {
|
impl TransitSimState {
|
||||||
pub fn new() -> TransitSimState {
|
pub fn new() -> TransitSimState {
|
||||||
TransitSimState {
|
TransitSimState {
|
||||||
buses: BTreeMap::new(),
|
buses: BTreeMap::new(),
|
||||||
|
routes: BTreeMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transitions
|
pub fn create_empty_route(&mut self, stops: Vec<BusStop>) -> RouteID {
|
||||||
pub fn bus_is_driving(&mut self, bus: CarID) {
|
assert!(stops.len() > 1);
|
||||||
self.buses.insert(bus, BusState::Driving);
|
let id = RouteID(self.routes.len());
|
||||||
|
self.routes.insert(
|
||||||
|
id,
|
||||||
|
Route {
|
||||||
|
id,
|
||||||
|
buses: Vec::new(),
|
||||||
|
stops: stops.clone(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bus_is_at_stop(&mut self, bus: CarID, stop: BusStop) {
|
// (next stop, start distance, first path)
|
||||||
self.buses.insert(bus, BusState::AtStop(stop));
|
pub fn get_route_starts(
|
||||||
|
&self,
|
||||||
|
id: RouteID,
|
||||||
|
map: &Map,
|
||||||
|
) -> Vec<(StopIdx, Distance, VecDeque<LaneID>)> {
|
||||||
|
let route = &self.routes[&id];
|
||||||
|
route
|
||||||
|
.stops
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(idx, stop1)| {
|
||||||
|
let next_stop = route.next_stop(idx);
|
||||||
|
let stop2 = &route.stops[next_stop];
|
||||||
|
let path = VecDeque::from(
|
||||||
|
map_model::pathfind(map, stop1.driving_lane, stop2.driving_lane).expect(
|
||||||
|
&format!("No route between bus stops {:?} and {:?}", stop1, stop2),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
(next_stop, stop1.dist_along, path)
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bus_created(&mut self, bus: CarID, route: RouteID, next_stop_idx: StopIdx) {
|
||||||
|
self.routes.get_mut(&route).unwrap().buses.push(bus);
|
||||||
|
self.buses.insert(
|
||||||
|
bus,
|
||||||
|
Bus {
|
||||||
|
car: bus,
|
||||||
|
route,
|
||||||
|
passengers: Vec::new(),
|
||||||
|
state: BusState::DrivingToStop(next_stop_idx),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns (should idle, new path)
|
||||||
|
pub fn get_action_when_stopped_at_end(
|
||||||
|
&mut self,
|
||||||
|
events: &mut Vec<Event>,
|
||||||
|
view: &CarView,
|
||||||
|
time: Tick,
|
||||||
|
map: &Map,
|
||||||
|
) -> (bool, Option<VecDeque<LaneID>>) {
|
||||||
|
let route = &self.routes[&self.buses[&view.id].route];
|
||||||
|
match self.buses[&view.id].state {
|
||||||
|
BusState::DrivingToStop(stop_idx) => {
|
||||||
|
let stop = &route.stops[stop_idx];
|
||||||
|
assert_eq!(stop.driving_lane, view.on.as_lane());
|
||||||
|
if stop.dist_along == view.dist_along {
|
||||||
|
// TODO constant for stop time
|
||||||
|
self.buses.get_mut(&view.id).unwrap().state =
|
||||||
|
BusState::AtStop(stop_idx, time + 10.0 * si::S);
|
||||||
|
events.push(Event::BusArrivedAtStop(view.id, stop.clone()));
|
||||||
|
if view.debug {
|
||||||
|
println!("{} arrived at stop {:?}, now waiting", view.id, stop);
|
||||||
|
}
|
||||||
|
return (true, None);
|
||||||
|
}
|
||||||
|
// No, keep creeping forwards
|
||||||
|
(false, None)
|
||||||
|
}
|
||||||
|
BusState::AtStop(stop_idx, wait_until) => {
|
||||||
|
let stop = &route.stops[stop_idx];
|
||||||
|
assert_eq!(stop.driving_lane, view.on.as_lane());
|
||||||
|
assert_eq!(stop.dist_along, view.dist_along);
|
||||||
|
|
||||||
|
if time == wait_until {
|
||||||
|
let next_stop = route.next_stop(stop_idx);
|
||||||
|
self.buses.get_mut(&view.id).unwrap().state =
|
||||||
|
BusState::DrivingToStop(next_stop);
|
||||||
|
events.push(Event::BusDepartedFromStop(view.id, stop.clone()));
|
||||||
|
if view.debug {
|
||||||
|
println!("{} departing from stop {:?}", view.id, stop);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut new_path = VecDeque::from(
|
||||||
|
map_model::pathfind(
|
||||||
|
map,
|
||||||
|
stop.driving_lane,
|
||||||
|
route.stops[next_stop].driving_lane,
|
||||||
|
).expect(&format!(
|
||||||
|
"No route between bus stops {:?} and {:?}",
|
||||||
|
stop, route.stops[next_stop]
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
new_path.pop_front();
|
||||||
|
|
||||||
|
return (true, Some(new_path));
|
||||||
|
}
|
||||||
|
|
||||||
|
(true, None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_dist_to_stop_at(&self, bus: CarID, driving_lane: LaneID) -> Distance {
|
||||||
|
match self.buses[&bus].state {
|
||||||
|
BusState::DrivingToStop(stop_idx) => {
|
||||||
|
let stop = &self.routes[&self.buses[&bus].route].stops[stop_idx];
|
||||||
|
assert_eq!(stop.driving_lane, driving_lane);
|
||||||
|
stop.dist_along
|
||||||
|
}
|
||||||
|
BusState::AtStop(_, _) => {
|
||||||
|
panic!("Shouldn't ask where to stop if the bus is already at a stop")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,18 +14,19 @@ fn bus_reaches_stops() {
|
|||||||
|
|
||||||
let stop1 = map.get_l(map_model::LaneID(309)).bus_stops[0].clone();
|
let stop1 = map.get_l(map_model::LaneID(309)).bus_stops[0].clone();
|
||||||
let stop2 = map.get_l(map_model::LaneID(840)).bus_stops[0].clone();
|
let stop2 = map.get_l(map_model::LaneID(840)).bus_stops[0].clone();
|
||||||
let bus = sim.seed_bus(vec![stop1.clone(), stop2.clone()], &map)
|
let buses = sim.seed_bus_route(vec![stop1.clone(), stop2.clone()], &map);
|
||||||
.unwrap();
|
let (bus1, bus2) = (buses[0], buses[1]);
|
||||||
|
|
||||||
sim::init::run_until_expectations_met(
|
sim::init::run_until_expectations_met(
|
||||||
&mut sim,
|
&mut sim,
|
||||||
&map,
|
&map,
|
||||||
&control_map,
|
&control_map,
|
||||||
|
// TODO assert stuff about bus2 as well, although the timing is a little unclear
|
||||||
vec![
|
vec![
|
||||||
sim::Event::BusArrivedAtStop(bus, stop2.clone()),
|
sim::Event::BusArrivedAtStop(bus1, stop2.clone()),
|
||||||
sim::Event::BusDepartedFromStop(bus, stop2),
|
sim::Event::BusDepartedFromStop(bus1, stop2),
|
||||||
sim::Event::BusArrivedAtStop(bus, stop1.clone()),
|
sim::Event::BusArrivedAtStop(bus1, stop1.clone()),
|
||||||
sim::Event::BusDepartedFromStop(bus, stop1),
|
sim::Event::BusDepartedFromStop(bus1, stop1),
|
||||||
],
|
],
|
||||||
sim::Tick::from_minutes(10),
|
sim::Tick::from_minutes(10),
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user