starting a blank scoreboard for sandbox mode. removing old defunct attempts at

score stuff first...
This commit is contained in:
Dustin Carlino 2019-06-13 13:36:19 -07:00
parent 4af3708237
commit e0edc4851d
15 changed files with 152 additions and 131 deletions

View File

@ -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 {

View File

@ -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;
}

View File

@ -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,

View File

@ -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()

View 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);
}
}

View File

@ -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

View File

@ -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();
}

View File

@ -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 {}

View File

@ -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,
}

View File

@ -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,

View File

@ -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);
}

View File

@ -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);
}
}
}

View File

@ -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>,
}

View File

@ -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> {

View File

@ -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>,
}