start figuring out what impact edits have on trips in a scenario. also,

count trips with the first path failing as aborted.
This commit is contained in:
Dustin Carlino 2019-11-11 14:14:19 -08:00
parent 1c139da0e0
commit 1ff80b2e20
5 changed files with 193 additions and 118 deletions

27
game/src/edit/impact.rs Normal file
View File

@ -0,0 +1,27 @@
use crate::ui::UI;
use abstutil::{prettyprint_usize, Timer};
use sim::Scenario;
// Edits have been applied.
pub fn edit_impacts(scenario: Option<Scenario>, ui: &mut UI, timer: &mut Timer) -> Vec<String> {
let mut lines = Vec::new();
if let Some(s) = scenario {
ui.primary.clear_sim();
s.instantiate(
&mut ui.primary.sim,
&ui.primary.map,
&mut ui.primary.current_flags.sim_flags.make_rng(),
timer,
);
lines.push(format!(
"{} aborted trips",
prettyprint_usize(ui.primary.sim.get_finished_trips().aborted_trips)
));
ui.primary.clear_sim();
} else {
lines.push("No scenario, so no trips impacted".to_string());
}
lines
}

View File

@ -1,9 +1,10 @@
mod impact;
mod stop_signs;
mod traffic_signals;
use crate::common::CommonState;
use crate::debug::DebugMode;
use crate::game::{State, Transition, WizardState};
use crate::game::{msg, State, Transition, WizardState};
use crate::helpers::{ColorScheme, ID};
use crate::render::{
DrawIntersection, DrawLane, DrawMap, DrawOptions, DrawRoad, DrawTurn, Renderable,
@ -38,6 +39,7 @@ impl EditMode {
(hotkey(Key::Escape), "back to sandbox mode"),
(hotkey(Key::S), "save edits"),
(hotkey(Key::L), "load different edits"),
(None, "measure impact of edits"),
],
ctx,
),
@ -114,6 +116,15 @@ impl State for EditMode {
// Parking state might've changed
ui.primary.clear_sim();
return Transition::Replace(Box::new(SandboxMode::new(ctx, ui, self.mode.clone())));
} else if self.menu.action("measure impact of edits") {
let mut timer = Timer::new("measure impact of edits");
ui.primary
.map
.recalculate_pathfinding_after_edits(&mut timer);
return Transition::Push(msg(
"Impact of edits",
impact::edit_impacts(self.mode.scenario(ui, &mut timer), ui, &mut timer),
));
}
if let Some(ID::Lane(id)) = ui.primary.current_selection {

View File

@ -47,6 +47,42 @@ pub trait GameplayState: downcast_rs::Downcast {
}
downcast_rs::impl_downcast!(GameplayState);
impl GameplayMode {
pub fn scenario(&self, ui: &UI, timer: &mut Timer) -> Option<Scenario> {
let name = match self {
GameplayMode::Freeform => {
return None;
}
GameplayMode::PlayScenario(ref scenario) => scenario,
_ => "weekday_typical_traffic_from_psrc",
};
let num_agents = ui.primary.current_flags.num_agents;
let builtin = if let Some(n) = num_agents {
format!("random scenario with {} agents", n)
} else {
"random scenario with some agents".to_string()
};
Some(if name == builtin {
if let Some(n) = num_agents {
Scenario::scaled_run(&ui.primary.map, n)
} else {
Scenario::small_run(&ui.primary.map)
}
} else if name == "just buses" {
let mut s = Scenario::empty(&ui.primary.map);
s.scenario_name = "just buses".to_string();
s.seed_buses = true;
s
} else {
abstutil::read_binary(
&abstutil::path1_bin(&ui.primary.map.get_name(), abstutil::SCENARIOS, &name),
timer,
)
.unwrap()
})
}
}
impl GameplayRunner {
pub fn initialize(mode: GameplayMode, ui: &mut UI, ctx: &mut EventCtx) -> GameplayRunner {
let prebaked: Analytics = abstutil::read_binary(
@ -58,61 +94,19 @@ impl GameplayRunner {
Analytics::new()
});
let ((menu, state), maybe_scenario) = match mode.clone() {
GameplayMode::Freeform => (freeform::Freeform::new(ctx), None),
GameplayMode::PlayScenario(scenario) => (
play_scenario::PlayScenario::new(&scenario, ctx),
Some(scenario),
),
GameplayMode::OptimizeBus(route_name) => (
optimize_bus::OptimizeBus::new(route_name, ctx, ui),
Some("weekday_typical_traffic_from_psrc".to_string()),
),
GameplayMode::CreateGridlock => (
create_gridlock::CreateGridlock::new(ctx),
Some("weekday_typical_traffic_from_psrc".to_string()),
),
GameplayMode::FasterTrips(trip_mode) => (
faster_trips::FasterTrips::new(trip_mode, ctx),
Some("weekday_typical_traffic_from_psrc".to_string()),
),
let (menu, state) = match mode.clone() {
GameplayMode::Freeform => freeform::Freeform::new(ctx),
GameplayMode::PlayScenario(scenario) => {
play_scenario::PlayScenario::new(&scenario, ctx)
}
GameplayMode::OptimizeBus(route_name) => {
optimize_bus::OptimizeBus::new(route_name, ctx, ui)
}
GameplayMode::CreateGridlock => create_gridlock::CreateGridlock::new(ctx),
GameplayMode::FasterTrips(trip_mode) => faster_trips::FasterTrips::new(trip_mode, ctx),
};
let runner = GameplayRunner {
mode,
menu: menu.disable_standalone_layout(),
state,
prebaked,
};
if let Some(scenario_name) = maybe_scenario {
ctx.loading_screen("instantiate scenario", |_, timer| {
let num_agents = ui.primary.current_flags.num_agents;
let builtin = if let Some(n) = num_agents {
format!("random scenario with {} agents", n)
} else {
"random scenario with some agents".to_string()
};
let scenario = if scenario_name == builtin {
if let Some(n) = num_agents {
Scenario::scaled_run(&ui.primary.map, n)
} else {
Scenario::small_run(&ui.primary.map)
}
} else if scenario_name == "just buses" {
let mut s = Scenario::empty(&ui.primary.map);
s.scenario_name = "just buses".to_string();
s.seed_buses = true;
s
} else {
abstutil::read_binary(
&abstutil::path1_bin(
&ui.primary.map.get_name(),
abstutil::SCENARIOS,
&scenario_name,
),
timer,
)
.unwrap()
};
ctx.loading_screen("instantiate scenario", |_, timer| {
if let Some(scenario) = mode.scenario(ui, timer) {
scenario.instantiate(
&mut ui.primary.sim,
&ui.primary.map,
@ -120,9 +114,14 @@ impl GameplayRunner {
timer,
);
ui.primary.sim.step(&ui.primary.map, Duration::seconds(0.1));
});
}
});
GameplayRunner {
mode,
menu: menu.disable_standalone_layout(),
state,
prebaked,
}
runner
}
pub fn event(

View File

@ -152,12 +152,15 @@ impl SidewalkPathfinder {
}
steps.push(PathStep::Turn(t));
current_i = Some(lane1.dst_i);
} else {
} else if let Some(t) = back_t {
if current_i != Some(lane1.src_i) {
steps.push(PathStep::ContraflowLane(lane1.id));
}
steps.push(PathStep::Turn(back_t.unwrap()));
steps.push(PathStep::Turn(t));
current_i = Some(lane1.src_i);
} else {
println!("WARNING! No turn between sidewalks {} and {}", lane1.id, l2);
return None;
}
}

View File

@ -172,11 +172,6 @@ impl TripSpawner {
timer.start_iter("spawn trips", paths.len());
for ((start_time, ped_id, car_id, spec), req, maybe_path) in paths {
timer.next();
if maybe_path.is_none() {
timer.warn(format!("Some trip couldn't find the first path {}", req));
continue;
}
let path = maybe_path.unwrap();
match spec {
TripSpec::CarAppearing {
start_pos,
@ -203,14 +198,22 @@ impl TripSpawner {
}
let trip_start = TripStart::Border(map.get_l(start_pos.lane()).src_i);
let trip = trips.new_trip(start_time, trip_start, legs);
let router = goal.make_router(path, map, vehicle.vehicle_type);
scheduler.quick_push(
start_time,
Command::SpawnCar(
CreateCar::for_appearing(vehicle, start_pos, router, trip),
retry_if_no_room,
),
);
if let Some(path) = maybe_path {
let router = goal.make_router(path, map, vehicle.vehicle_type);
scheduler.quick_push(
start_time,
Command::SpawnCar(
CreateCar::for_appearing(vehicle, start_pos, router, trip),
retry_if_no_room,
),
);
} else {
timer.warn(format!(
"CarAppearing trip couldn't find the first path {}",
req
));
trips.abort_trip_failed_start(trip);
}
}
TripSpec::UsingParkedCar {
start,
@ -243,17 +246,25 @@ impl TripSpawner {
let trip =
trips.new_trip(start_time, TripStart::Bldg(vehicle.owner.unwrap()), legs);
scheduler.quick_push(
start_time,
Command::SpawnPed(CreatePedestrian {
id: ped_id.unwrap(),
speed: ped_speed,
start,
goal: parking_spot,
path,
trip,
}),
);
if let Some(path) = maybe_path {
scheduler.quick_push(
start_time,
Command::SpawnPed(CreatePedestrian {
id: ped_id.unwrap(),
speed: ped_speed,
start,
goal: parking_spot,
path,
trip,
}),
);
} else {
timer.warn(format!(
"UsingParkedCar trip couldn't find the first path {}",
req
));
trips.abort_trip_failed_start(trip);
}
}
TripSpec::MaybeUsingParkedCar {
start_bldg,
@ -273,8 +284,8 @@ impl TripSpawner {
speed: ped_speed,
start: SidewalkSpot::building(start_bldg, map),
goal: walk_to,
// This is junk
path,
// This is guaranteed to work, and is junk anyway.
path: maybe_path.unwrap(),
trip,
}),
);
@ -297,17 +308,25 @@ impl TripSpawner {
vec![TripLeg::Walk(ped_id.unwrap(), ped_speed, goal.clone())],
);
scheduler.quick_push(
start_time,
Command::SpawnPed(CreatePedestrian {
id: ped_id.unwrap(),
speed: ped_speed,
start,
goal,
path,
trip,
}),
);
if let Some(path) = maybe_path {
scheduler.quick_push(
start_time,
Command::SpawnPed(CreatePedestrian {
id: ped_id.unwrap(),
speed: ped_speed,
start,
goal,
path,
trip,
}),
);
} else {
timer.warn(format!(
"JustWalking trip couldn't find the first path {}",
req
));
trips.abort_trip_failed_start(trip);
}
}
TripSpec::UsingBike {
start,
@ -344,17 +363,25 @@ impl TripSpawner {
legs,
);
scheduler.quick_push(
start_time,
Command::SpawnPed(CreatePedestrian {
id: ped_id.unwrap(),
speed: ped_speed,
start,
goal: walk_to,
path,
trip,
}),
);
if let Some(path) = maybe_path {
scheduler.quick_push(
start_time,
Command::SpawnPed(CreatePedestrian {
id: ped_id.unwrap(),
speed: ped_speed,
start,
goal: walk_to,
path,
trip,
}),
);
} else {
timer.warn(format!(
"UsingBike trip couldn't find the first path {}",
req
));
trips.abort_trip_failed_start(trip);
}
}
TripSpec::UsingTransit {
start,
@ -382,17 +409,25 @@ impl TripSpawner {
],
);
scheduler.quick_push(
start_time,
Command::SpawnPed(CreatePedestrian {
id: ped_id.unwrap(),
speed: ped_speed,
start,
goal: walk_to,
path,
trip,
}),
);
if let Some(path) = maybe_path {
scheduler.quick_push(
start_time,
Command::SpawnPed(CreatePedestrian {
id: ped_id.unwrap(),
speed: ped_speed,
start,
goal: walk_to,
path,
trip,
}),
);
} else {
timer.warn(format!(
"UsingTransit trip couldn't find the first path {}",
req
));
trips.abort_trip_failed_start(trip);
}
}
}
}