mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-26 07:52:05 +03:00
starting a blank scoreboard for sandbox mode. removing old defunct attempts at
score stuff first...
This commit is contained in:
parent
4af3708237
commit
e0edc4851d
@ -305,12 +305,12 @@ pub struct DiffAllTrips {
|
||||
|
||||
impl DiffAllTrips {
|
||||
fn new(primary: &mut PerMapUI, secondary: &mut PerMapUI) -> DiffAllTrips {
|
||||
let stats1 = primary.sim.get_stats(&primary.map);
|
||||
let stats2 = secondary.sim.get_stats(&secondary.map);
|
||||
let trip_positions1 = primary.sim.get_trip_positions(&primary.map);
|
||||
let trip_positions2 = secondary.sim.get_trip_positions(&secondary.map);
|
||||
let mut same_trips = 0;
|
||||
let mut lines: Vec<Line> = Vec::new();
|
||||
for (trip, pt1) in &stats1.canonical_pt_per_trip {
|
||||
if let Some(pt2) = stats2.canonical_pt_per_trip.get(trip) {
|
||||
for (trip, pt1) in &trip_positions1.canonical_pt_per_trip {
|
||||
if let Some(pt2) = trip_positions2.canonical_pt_per_trip.get(trip) {
|
||||
if let Some(l) = Line::maybe_new(*pt1, *pt2) {
|
||||
lines.push(l);
|
||||
} else {
|
||||
|
@ -5,7 +5,6 @@ use abstutil;
|
||||
use ezgui::{Color, Drawable, GfxCtx, ModalMenu, Prerender, Text};
|
||||
use geom::{Duration, Polygon, Pt2D};
|
||||
use map_model::{LaneID, Map, Neighborhood};
|
||||
use sim::Sim;
|
||||
use std::collections::HashSet;
|
||||
|
||||
pub struct NeighborhoodSummary {
|
||||
@ -55,7 +54,7 @@ impl NeighborhoodSummary {
|
||||
if self.active && Some(ui.primary.sim.time()) != self.last_summary {
|
||||
self.last_summary = Some(ui.primary.sim.time());
|
||||
for r in self.regions.iter_mut() {
|
||||
r.update_summary(&ui.primary.sim);
|
||||
r.update_summary();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -105,13 +104,12 @@ impl Region {
|
||||
}
|
||||
}
|
||||
|
||||
fn update_summary(&mut self, primary: &Sim) {
|
||||
fn update_summary(&mut self) {
|
||||
let mut txt = Text::new();
|
||||
txt.add_styled_line(self.name.clone(), None, Some(Color::GREEN), Some(50));
|
||||
txt.add_line(format!("contains {} lanes", self.lanes.len()));
|
||||
|
||||
let s1 = primary.summarize(&self.lanes);
|
||||
|
||||
/*let s1 = primary.summarize(&self.lanes);
|
||||
txt.add_line(format!(
|
||||
"{} cars parked, {} spots free",
|
||||
s1.cars_parked, s1.open_parking_spots
|
||||
@ -124,7 +122,7 @@ impl Region {
|
||||
"{} moving peds, {} stuck",
|
||||
s1.moving_peds, s1.stuck_peds
|
||||
));
|
||||
txt.add_line(format!("{} buses", s1.buses));
|
||||
txt.add_line(format!("{} buses", s1.buses));*/
|
||||
|
||||
self.summary = txt;
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
mod route_explorer;
|
||||
mod route_viewer;
|
||||
mod score;
|
||||
mod show_activity;
|
||||
mod spawner;
|
||||
mod time_travel;
|
||||
@ -33,6 +34,7 @@ enum State {
|
||||
TimeTraveling,
|
||||
ExploringRoute(route_explorer::RouteExplorer),
|
||||
JumpingToTime(Wizard),
|
||||
Scoreboard(score::Scoreboard),
|
||||
}
|
||||
|
||||
impl SandboxMode {
|
||||
@ -68,6 +70,7 @@ impl SandboxMode {
|
||||
(hotkey(Key::L), "show/hide route for all agents"),
|
||||
(hotkey(Key::A), "show/hide active traffic"),
|
||||
(hotkey(Key::T), "start time traveling"),
|
||||
(hotkey(Key::Q), "scoreboard"),
|
||||
(lctrl(Key::D), "debug mode"),
|
||||
(lctrl(Key::E), "edit mode"),
|
||||
],
|
||||
@ -146,6 +149,13 @@ impl SandboxMode {
|
||||
}
|
||||
EventLoopMode::InputOnly
|
||||
}
|
||||
State::Scoreboard(ref mut s) => {
|
||||
if s.event(ctx) {
|
||||
mode.state = State::Playing;
|
||||
mode.speed.pause();
|
||||
}
|
||||
EventLoopMode::InputOnly
|
||||
}
|
||||
State::Playing => {
|
||||
mode.time_travel.record(&state.ui);
|
||||
|
||||
@ -238,6 +248,10 @@ impl SandboxMode {
|
||||
mode.time_travel.start(ctx, &state.ui);
|
||||
return EventLoopMode::InputOnly;
|
||||
}
|
||||
if mode.menu.action("scoreboard") {
|
||||
mode.state = State::Scoreboard(score::Scoreboard::new(ctx, &state.ui));
|
||||
return EventLoopMode::InputOnly;
|
||||
}
|
||||
|
||||
if mode.menu.action("quit") {
|
||||
state.mode = Mode::SplashScreen(Wizard::new(), None);
|
||||
@ -400,6 +414,15 @@ impl SandboxMode {
|
||||
);
|
||||
wizard.draw(g);
|
||||
}
|
||||
State::Scoreboard(ref s) => {
|
||||
state.ui.draw(
|
||||
g,
|
||||
DrawOptions::new(),
|
||||
&state.ui.primary.sim,
|
||||
&ShowEverything::new(),
|
||||
);
|
||||
s.draw(g);
|
||||
}
|
||||
_ => {
|
||||
state.ui.draw(
|
||||
g,
|
||||
|
@ -120,7 +120,7 @@ fn debug_all_routes(ui: &mut UI) -> RouteViewer {
|
||||
let trips: Vec<TripID> = ui
|
||||
.primary
|
||||
.sim
|
||||
.get_stats(&ui.primary.map)
|
||||
.get_trip_positions(&ui.primary.map)
|
||||
.canonical_pt_per_trip
|
||||
.keys()
|
||||
.cloned()
|
||||
|
37
editor/src/sandbox/score.rs
Normal file
37
editor/src/sandbox/score.rs
Normal file
@ -0,0 +1,37 @@
|
||||
use crate::ui::UI;
|
||||
use ezgui::{
|
||||
hotkey, EventCtx, GfxCtx, HorizontalAlignment, Key, ModalMenu, Text, VerticalAlignment,
|
||||
};
|
||||
|
||||
pub struct Scoreboard {
|
||||
menu: ModalMenu,
|
||||
summary: Text,
|
||||
}
|
||||
|
||||
impl Scoreboard {
|
||||
pub fn new(ctx: &mut EventCtx, ui: &UI) -> Scoreboard {
|
||||
let menu = ModalMenu::new("Scoreboard", vec![(hotkey(Key::Escape), "quit")], ctx);
|
||||
|
||||
let mut summary = Text::new();
|
||||
summary.push(format!("Score at [red:{}]", ui.primary.sim.time()));
|
||||
|
||||
Scoreboard { menu, summary }
|
||||
}
|
||||
|
||||
// Returns true if done and we should go back to main sandbox mode.
|
||||
pub fn event(&mut self, ctx: &mut EventCtx) -> bool {
|
||||
self.menu.handle_event(ctx, None);
|
||||
if self.menu.action("quit") {
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn draw(&self, g: &mut GfxCtx) {
|
||||
g.draw_blocking_text(
|
||||
&self.summary,
|
||||
(HorizontalAlignment::Center, VerticalAlignment::Center),
|
||||
);
|
||||
self.menu.draw(g);
|
||||
}
|
||||
}
|
@ -131,8 +131,8 @@ impl Heatmap {
|
||||
|
||||
fn active_agent_heatmap(ctx: &EventCtx, ui: &mut UI) -> Heatmap {
|
||||
let mut h = Heatmap::new(ctx.canvas.get_screen_bounds());
|
||||
let stats = ui.primary.sim.get_stats(&ui.primary.map);
|
||||
for pt in stats.canonical_pt_per_trip.values() {
|
||||
let trip_positions = ui.primary.sim.get_trip_positions(&ui.primary.map);
|
||||
for pt in trip_positions.canonical_pt_per_trip.values() {
|
||||
h.add(*pt);
|
||||
}
|
||||
h
|
||||
|
@ -85,7 +85,7 @@ fn main() {
|
||||
None,
|
||||
);
|
||||
timer.done();
|
||||
println!("{:?}", sim.get_score());
|
||||
println!("Done at {}", sim.time());
|
||||
if flags.enable_profiler && save_at.is_none() {
|
||||
cpuprofiler::PROFILER.lock().unwrap().stop().unwrap();
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
mod events;
|
||||
mod make;
|
||||
mod mechanics;
|
||||
mod query;
|
||||
mod render;
|
||||
mod router;
|
||||
mod scheduler;
|
||||
@ -11,23 +10,23 @@ mod trips;
|
||||
|
||||
pub use self::events::Event;
|
||||
pub use self::make::{
|
||||
ABTest, ABTestResults, BorderSpawnOverTime, OriginDestination, Scenario, SeedParkedCars,
|
||||
SimFlags, SpawnOverTime, SpawnTrip, TripSpawner, TripSpec,
|
||||
ABTest, BorderSpawnOverTime, OriginDestination, Scenario, SeedParkedCars, SimFlags,
|
||||
SpawnOverTime, SpawnTrip, TripSpawner, TripSpec,
|
||||
};
|
||||
pub(crate) use self::mechanics::{
|
||||
DrivingSimState, IntersectionSimState, ParkingSimState, WalkingSimState,
|
||||
};
|
||||
pub use self::query::{ScoreSummary, SimStats, Summary};
|
||||
pub(crate) use self::router::{ActionAtEnd, Router};
|
||||
pub(crate) use self::scheduler::{Command, Scheduler};
|
||||
pub use self::sim::Sim;
|
||||
pub(crate) use self::transit::TransitSimState;
|
||||
pub(crate) use self::trips::{TripLeg, TripManager};
|
||||
pub(crate) use self::trips::{FinishedTrips, TripLeg, TripManager};
|
||||
pub use crate::render::{CarStatus, DrawCarInput, DrawPedestrianInput, GetDrawAgents};
|
||||
use abstutil::Cloneable;
|
||||
use geom::{Distance, Duration, Speed};
|
||||
use geom::{Distance, Duration, Pt2D, Speed};
|
||||
use map_model::{BuildingID, BusStopID, IntersectionID, LaneID, LaneType, Map, Path, Position};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::collections::BTreeMap;
|
||||
use std::fmt;
|
||||
|
||||
// http://pccsc.net/bicycle-parking-info/ says 68 inches, which is 1.73m
|
||||
@ -439,6 +438,21 @@ impl CreateCar {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq)]
|
||||
pub struct TripPositions {
|
||||
pub time: Duration,
|
||||
pub canonical_pt_per_trip: BTreeMap<TripID, Pt2D>,
|
||||
}
|
||||
|
||||
impl TripPositions {
|
||||
pub(crate) fn new(time: Duration) -> TripPositions {
|
||||
TripPositions {
|
||||
time,
|
||||
canonical_pt_per_trip: BTreeMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We have to do this in the crate where these types are defined. Bit annoying, since it's really
|
||||
// kind of an ezgui concept.
|
||||
impl Cloneable for ABTest {}
|
||||
|
@ -1,4 +1,3 @@
|
||||
use crate::ScoreSummary;
|
||||
use abstutil;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
@ -24,10 +23,3 @@ impl ABTest {
|
||||
abstutil::save_json_object("ab_tests", &self.map_name, &self.test_name, self);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct ABTestResults {
|
||||
pub test_name: String,
|
||||
pub run1_score: ScoreSummary,
|
||||
pub run2_score: ScoreSummary,
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ mod load;
|
||||
mod scenario;
|
||||
mod spawner;
|
||||
|
||||
pub use self::a_b_test::{ABTest, ABTestResults};
|
||||
pub use self::a_b_test::ABTest;
|
||||
pub use self::load::SimFlags;
|
||||
pub use self::scenario::{
|
||||
BorderSpawnOverTime, OriginDestination, Scenario, SeedParkedCars, SpawnOverTime, SpawnTrip,
|
||||
|
@ -2,8 +2,8 @@ use crate::mechanics::car::{Car, CarState};
|
||||
use crate::mechanics::queue::Queue;
|
||||
use crate::{
|
||||
ActionAtEnd, AgentID, CarID, Command, CreateCar, DistanceInterval, DrawCarInput,
|
||||
IntersectionSimState, ParkedCar, ParkingSimState, Scheduler, SimStats, TimeInterval,
|
||||
TransitSimState, TripManager, VehicleType, WalkingSimState, FOLLOWING_DISTANCE,
|
||||
IntersectionSimState, ParkedCar, ParkingSimState, Scheduler, TimeInterval, TransitSimState,
|
||||
TripManager, TripPositions, VehicleType, WalkingSimState, FOLLOWING_DISTANCE,
|
||||
};
|
||||
use abstutil::{deserialize_btreemap, serialize_btreemap};
|
||||
use geom::{Distance, Duration, PolyLine, Pt2D};
|
||||
@ -648,14 +648,16 @@ impl DrivingSimState {
|
||||
(cars, bikes, buses)
|
||||
}
|
||||
|
||||
pub fn populate_stats(&self, stats: &mut SimStats, map: &Map) {
|
||||
pub fn populate_trip_positions(&self, trip_positions: &mut TripPositions, map: &Map) {
|
||||
for queue in self.queues.values() {
|
||||
if queue.cars.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (car, dist) in queue.get_car_positions(stats.time, &self.cars, &self.queues) {
|
||||
stats
|
||||
for (car, dist) in
|
||||
queue.get_car_positions(trip_positions.time, &self.cars, &self.queues)
|
||||
{
|
||||
trip_positions
|
||||
.canonical_pt_per_trip
|
||||
.insert(self.cars[&car].trip, queue.id.dist_along(dist, map).0);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
AgentID, Command, CreatePedestrian, DistanceInterval, DrawPedestrianInput,
|
||||
IntersectionSimState, ParkingSimState, PedestrianID, Scheduler, SidewalkPOI, SidewalkSpot,
|
||||
SimStats, TimeInterval, TransitSimState, TripID, TripManager,
|
||||
TimeInterval, TransitSimState, TripID, TripManager, TripPositions,
|
||||
};
|
||||
use abstutil::{deserialize_multimap, serialize_multimap, MultiMap};
|
||||
use geom::{Distance, Duration, Line, PolyLine, Pt2D, Speed};
|
||||
@ -272,11 +272,11 @@ impl WalkingSimState {
|
||||
peds
|
||||
}
|
||||
|
||||
pub fn populate_stats(&self, stats: &mut SimStats, map: &Map) {
|
||||
pub fn populate_trip_positions(&self, trip_positions: &mut TripPositions, map: &Map) {
|
||||
for ped in self.peds.values() {
|
||||
stats
|
||||
trip_positions
|
||||
.canonical_pt_per_trip
|
||||
.insert(ped.trip, ped.get_draw_ped(stats.time, map).pos);
|
||||
.insert(ped.trip, ped.get_draw_ped(trip_positions.time, map).pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,53 +0,0 @@
|
||||
use crate::TripID;
|
||||
use geom::{Duration, Pt2D};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq)]
|
||||
pub struct SimStats {
|
||||
pub time: Duration,
|
||||
pub canonical_pt_per_trip: BTreeMap<TripID, Pt2D>,
|
||||
}
|
||||
|
||||
impl SimStats {
|
||||
pub(crate) fn new(time: Duration) -> SimStats {
|
||||
SimStats {
|
||||
time,
|
||||
canonical_pt_per_trip: BTreeMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO This is totally unused, needs to be re-thought
|
||||
// TODO moving vs stuck shouldn't be an instantaneous judgment -- stuck is if there's an agent
|
||||
// directly in front limiting speed significantly, or if an intersection isn't allowing movement
|
||||
// yet
|
||||
pub struct Summary {
|
||||
pub cars_parked: usize,
|
||||
pub open_parking_spots: usize,
|
||||
pub moving_cars: usize,
|
||||
pub stuck_cars: usize,
|
||||
pub moving_peds: usize,
|
||||
pub stuck_peds: usize,
|
||||
pub buses: usize,
|
||||
// The agent in one or both worlds is in the requested set of lanes.
|
||||
pub trips_with_ab_test_divergence: usize,
|
||||
}
|
||||
|
||||
// TODO This is totally unused, needs to be re-thought
|
||||
// As of a moment in time, not necessarily the end of the simulation
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct ScoreSummary {
|
||||
pub pending_walking_trips: usize,
|
||||
pub total_walking_trips: usize,
|
||||
pub total_walking_trip_time: Duration,
|
||||
|
||||
pub pending_driving_trips: usize,
|
||||
pub total_driving_trips: usize,
|
||||
pub total_driving_trip_time: Duration,
|
||||
|
||||
// If filled out, the sim took this long to complete.
|
||||
// TODO This is maybe not a useful thing to measure; the agents moving at the end don't have
|
||||
// others around, so things are stranger for them.
|
||||
pub completion_time: Option<Duration>,
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
use crate::{
|
||||
AgentID, CarID, Command, CreateCar, DrawCarInput, DrawPedestrianInput, DrivingGoal,
|
||||
DrivingSimState, Event, GetDrawAgents, IntersectionSimState, ParkedCar, ParkingSimState,
|
||||
ParkingSpot, PedestrianID, Router, Scheduler, ScoreSummary, SimStats, Summary, TransitSimState,
|
||||
TripID, TripLeg, TripManager, TripSpawner, TripSpec, VehicleSpec, VehicleType, WalkingSimState,
|
||||
BUS_LENGTH,
|
||||
DrivingSimState, Event, FinishedTrips, GetDrawAgents, IntersectionSimState, ParkedCar,
|
||||
ParkingSimState, ParkingSpot, PedestrianID, Router, Scheduler, TransitSimState, TripID,
|
||||
TripLeg, TripManager, TripPositions, TripSpawner, TripSpec, VehicleSpec, VehicleType,
|
||||
WalkingSimState, BUS_LENGTH,
|
||||
};
|
||||
use abstutil::{elapsed_seconds, Timer};
|
||||
use derivative::Derivative;
|
||||
@ -45,7 +45,7 @@ pub struct Sim {
|
||||
// Lazily computed.
|
||||
#[derivative(PartialEq = "ignore")]
|
||||
#[serde(skip_serializing, skip_deserializing)]
|
||||
stats: Option<SimStats>,
|
||||
trip_positions: Option<TripPositions>,
|
||||
|
||||
#[derivative(PartialEq = "ignore")]
|
||||
#[serde(skip_serializing, skip_deserializing)]
|
||||
@ -78,7 +78,7 @@ impl Sim {
|
||||
edits_name: "no_edits".to_string(),
|
||||
run_name,
|
||||
step_count: 0,
|
||||
stats: None,
|
||||
trip_positions: None,
|
||||
events_since_last_step: Vec::new(),
|
||||
}
|
||||
}
|
||||
@ -408,7 +408,7 @@ impl Sim {
|
||||
}
|
||||
self.time = target_time;
|
||||
|
||||
self.stats = None;
|
||||
self.trip_positions = None;
|
||||
|
||||
self.events_since_last_step.clear();
|
||||
self.events_since_last_step
|
||||
@ -599,20 +599,6 @@ impl Sim {
|
||||
self.time == Duration::ZERO && self.is_done()
|
||||
}
|
||||
|
||||
// TODO Rethink this
|
||||
pub fn summarize(&self, _lanes: &HashSet<LaneID>) -> Summary {
|
||||
Summary {
|
||||
cars_parked: 0,
|
||||
open_parking_spots: 0,
|
||||
moving_cars: 0,
|
||||
stuck_cars: 0,
|
||||
buses: 0,
|
||||
moving_peds: 0,
|
||||
stuck_peds: 0,
|
||||
trips_with_ab_test_divergence: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn summary(&self) -> String {
|
||||
let (active, unfinished) = self.trips.num_trips();
|
||||
format!(
|
||||
@ -623,17 +609,8 @@ impl Sim {
|
||||
)
|
||||
}
|
||||
|
||||
// TODO Rethink this
|
||||
pub fn get_score(&self) -> ScoreSummary {
|
||||
ScoreSummary {
|
||||
pending_walking_trips: 0,
|
||||
total_walking_trips: 0,
|
||||
total_walking_trip_time: Duration::ZERO,
|
||||
pending_driving_trips: 0,
|
||||
total_driving_trips: 0,
|
||||
total_driving_trip_time: Duration::ZERO,
|
||||
completion_time: None,
|
||||
}
|
||||
pub fn get_finished_trips(&self) -> FinishedTrips {
|
||||
self.trips.get_finished_trips()
|
||||
}
|
||||
|
||||
pub fn debug_ped(&self, id: PedestrianID) {
|
||||
@ -740,17 +717,19 @@ impl Sim {
|
||||
.or_else(|| self.parking.get_owner_of_car(id))
|
||||
}
|
||||
|
||||
pub fn get_stats(&mut self, map: &Map) -> &SimStats {
|
||||
if self.stats.is_some() {
|
||||
return self.stats.as_ref().unwrap();
|
||||
pub fn get_trip_positions(&mut self, map: &Map) -> &TripPositions {
|
||||
if self.trip_positions.is_some() {
|
||||
return self.trip_positions.as_ref().unwrap();
|
||||
}
|
||||
|
||||
let mut stats = SimStats::new(self.time);
|
||||
self.driving.populate_stats(&mut stats, map);
|
||||
self.walking.populate_stats(&mut stats, map);
|
||||
let mut trip_positions = TripPositions::new(self.time);
|
||||
self.driving
|
||||
.populate_trip_positions(&mut trip_positions, map);
|
||||
self.walking
|
||||
.populate_trip_positions(&mut trip_positions, map);
|
||||
|
||||
self.stats = Some(stats);
|
||||
self.stats.as_ref().unwrap()
|
||||
self.trip_positions = Some(trip_positions);
|
||||
self.trip_positions.as_ref().unwrap()
|
||||
}
|
||||
|
||||
pub fn get_events_since_last_step(&self) -> &Vec<Event> {
|
||||
|
@ -379,6 +379,18 @@ impl TripManager {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_finished_trips(&self) -> FinishedTrips {
|
||||
FinishedTrips {
|
||||
pending_walking_trips: 0,
|
||||
total_walking_trips: 0,
|
||||
total_walking_trip_time: Duration::ZERO,
|
||||
pending_driving_trips: 0,
|
||||
total_driving_trips: 0,
|
||||
total_driving_trip_time: Duration::ZERO,
|
||||
completion_time: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_done(&self) -> bool {
|
||||
self.unfinished_trips == 0
|
||||
}
|
||||
@ -467,3 +479,20 @@ pub enum TripLeg {
|
||||
RideBus(PedestrianID, BusRouteID, BusStopID),
|
||||
ServeBusRoute(CarID, BusRouteID),
|
||||
}
|
||||
|
||||
// As of a moment in time, not necessarily the end of the simulation
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct FinishedTrips {
|
||||
pub pending_walking_trips: usize,
|
||||
pub total_walking_trips: usize,
|
||||
pub total_walking_trip_time: Duration,
|
||||
|
||||
pub pending_driving_trips: usize,
|
||||
pub total_driving_trips: usize,
|
||||
pub total_driving_trip_time: Duration,
|
||||
|
||||
// If filled out, the sim took this long to complete.
|
||||
// TODO This is maybe not a useful thing to measure; the agents moving at the end don't have
|
||||
// others around, so things are stranger for them.
|
||||
pub completion_time: Option<Duration>,
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user