diff --git a/editor/src/abtest/mod.rs b/editor/src/abtest/mod.rs index d2cc1e41c9..adc28cd397 100644 --- a/editor/src/abtest/mod.rs +++ b/editor/src/abtest/mod.rs @@ -11,7 +11,7 @@ use ezgui::{hotkey, Color, EventCtx, EventLoopMode, GeomBatch, GfxCtx, Key, Moda use geom::{Circle, Distance, Line, PolyLine}; use map_model::{Map, LANE_THICKNESS}; use serde_derive::{Deserialize, Serialize}; -use sim::{Sim, TripID}; +use sim::{Sim, SimOptions, TripID}; pub struct ABTestMode { menu: ModalMenu, @@ -245,17 +245,13 @@ impl ABTestMode { // Temporarily move everything into this structure. let blank_map = Map::blank(); let mut secondary = ui.secondary.take().unwrap(); + let mut opts = SimOptions::new("run"); + opts.use_freeform_policy_everywhere = ui.primary.current_flags.sim_flags.freeform_policy; let ss = ABTestSavestate { primary_map: std::mem::replace(&mut ui.primary.map, Map::blank()), - primary_sim: std::mem::replace( - &mut ui.primary.sim, - Sim::new(&blank_map, "run".to_string(), None), - ), + primary_sim: std::mem::replace(&mut ui.primary.sim, Sim::new(&blank_map, opts.clone())), secondary_map: std::mem::replace(&mut secondary.map, Map::blank()), - secondary_sim: std::mem::replace( - &mut secondary.sim, - Sim::new(&blank_map, "run".to_string(), None), - ), + secondary_sim: std::mem::replace(&mut secondary.sim, Sim::new(&blank_map, opts)), }; let path = abstutil::path2_bin( diff --git a/editor/src/abtest/setup.rs b/editor/src/abtest/setup.rs index 1c325784c2..3973705309 100644 --- a/editor/src/abtest/setup.rs +++ b/editor/src/abtest/setup.rs @@ -155,6 +155,7 @@ fn launch_test(test: &ABTest, ui: &mut UI, ctx: &mut EventCtx) -> ABTestMode { load, rng_seed: current_flags.sim_flags.rng_seed, run_name: Some(format!("{} with {}", test.test_name, test.edits2_name)), + freeform_policy: current_flags.sim_flags.freeform_policy, }, ..current_flags.clone() }, diff --git a/editor/src/ui.rs b/editor/src/ui.rs index 089d0674cd..6fde1670ef 100644 --- a/editor/src/ui.rs +++ b/editor/src/ui.rs @@ -10,7 +10,7 @@ use geom::{Bounds, Circle, Distance}; use map_model::{Map, Traversable}; use rand::seq::SliceRandom; use serde_derive::{Deserialize, Serialize}; -use sim::{GetDrawAgents, Sim, SimFlags}; +use sim::{GetDrawAgents, Sim, SimFlags, SimOptions}; use structopt::StructOpt; pub struct UI { @@ -489,15 +489,19 @@ impl PerMapUI { } pub fn reset_sim(&mut self) { + let flags = &self.current_flags.sim_flags; + // TODO savestate_every gets lost self.sim = Sim::new( &self.map, - self.current_flags - .sim_flags - .run_name - .clone() - .unwrap_or_else(|| "unnamed".to_string()), - None, + SimOptions { + run_name: flags + .run_name + .clone() + .unwrap_or_else(|| "unnamed".to_string()), + savestate_every: None, + use_freeform_policy_everywhere: flags.freeform_policy, + }, ); } } diff --git a/sim/src/lib.rs b/sim/src/lib.rs index 9769388b8b..4343b26c0f 100644 --- a/sim/src/lib.rs +++ b/sim/src/lib.rs @@ -18,7 +18,7 @@ pub(crate) use self::mechanics::{ }; pub(crate) use self::router::{ActionAtEnd, Router}; pub(crate) use self::scheduler::{Command, Scheduler}; -pub use self::sim::Sim; +pub use self::sim::{Sim, SimOptions}; pub(crate) use self::transit::TransitSimState; pub use self::trips::{FinishedTrips, TripEnd, TripMode, TripStart, TripStatus}; pub(crate) use self::trips::{TripLeg, TripManager}; diff --git a/sim/src/make/load.rs b/sim/src/make/load.rs index 76ab891e50..3976edf88b 100644 --- a/sim/src/make/load.rs +++ b/sim/src/make/load.rs @@ -1,4 +1,4 @@ -use crate::{Scenario, Sim}; +use crate::{Scenario, Sim, SimOptions}; use abstutil; use geom::Duration; use map_model::{Map, MapEdits}; @@ -25,6 +25,10 @@ pub struct SimFlags { /// Run name for savestating #[structopt(long = "run_name")] pub run_name: Option, + + /// Use freeform intersection policy everywhere + #[structopt(long = "freeform_policy")] + pub freeform_policy: bool, } impl SimFlags { @@ -38,6 +42,7 @@ impl SimFlags { load: PathBuf::from(abstutil::path_map(map)), rng_seed: Some(42), run_name: Some(run_name.to_string()), + freeform_policy: false, } } @@ -57,6 +62,15 @@ impl SimFlags { ) -> (Map, Sim, XorShiftRng) { let mut rng = self.make_rng(); + let mut opts = SimOptions { + run_name: self + .run_name + .clone() + .unwrap_or_else(|| "unnamed".to_string()), + savestate_every, + use_freeform_policy_everywhere: self.freeform_policy, + }; + if self.load.starts_with(Path::new("../data/save/")) { timer.note(format!("Resuming from {}", self.load.display())); @@ -81,13 +95,11 @@ impl SimFlags { let map: Map = abstutil::read_binary(&abstutil::path_map(&scenario.map_name), timer).unwrap(); - let mut sim = Sim::new( - &map, - self.run_name - .clone() - .unwrap_or_else(|| scenario.scenario_name.clone()), - savestate_every, - ); + opts.run_name = self + .run_name + .clone() + .unwrap_or_else(|| scenario.scenario_name.clone()); + let mut sim = Sim::new(&map, opts); scenario.instantiate(&mut sim, &map, &mut rng, timer); (map, sim, rng) @@ -98,13 +110,7 @@ impl SimFlags { .expect(&format!("Couldn't load map from {}", self.load.display())); timer.start("create sim"); - let sim = Sim::new( - &map, - self.run_name - .clone() - .unwrap_or_else(|| "unnamed".to_string()), - savestate_every, - ); + let sim = Sim::new(&map, opts); timer.stop("create sim"); (map, sim, rng) @@ -115,13 +121,7 @@ impl SimFlags { .expect(&format!("Couldn't load map from {}", self.load.display())); timer.start("create sim"); - let sim = Sim::new( - &map, - self.run_name - .clone() - .unwrap_or_else(|| "unnamed".to_string()), - savestate_every, - ); + let sim = Sim::new(&map, opts); timer.stop("create sim"); (map, sim, rng) diff --git a/sim/src/mechanics/intersection.rs b/sim/src/mechanics/intersection.rs index 0ae902e081..12981cd2fc 100644 --- a/sim/src/mechanics/intersection.rs +++ b/sim/src/mechanics/intersection.rs @@ -15,6 +15,7 @@ const WAIT_AT_STOP_SIGN: Duration = Duration::const_seconds(0.5); #[derive(Serialize, Deserialize, PartialEq)] pub struct IntersectionSimState { state: BTreeMap, + use_freeform_policy_everywhere: bool, } #[derive(Serialize, Deserialize, PartialEq)] @@ -30,9 +31,14 @@ struct State { } impl IntersectionSimState { - pub fn new(map: &Map, scheduler: &mut Scheduler) -> IntersectionSimState { + pub fn new( + map: &Map, + scheduler: &mut Scheduler, + use_freeform_policy_everywhere: bool, + ) -> IntersectionSimState { let mut sim = IntersectionSimState { state: BTreeMap::new(), + use_freeform_policy_everywhere, }; for i in map.all_intersections() { sim.state.insert( @@ -133,13 +139,14 @@ impl IntersectionSimState { let state = self.state.get_mut(&turn.parent).unwrap(); state.waiting.entry(req.clone()).or_insert(now); - let allowed = if let Some(ref signal) = map.maybe_get_traffic_signal(state.id) { + let allowed = if self.use_freeform_policy_everywhere { + state.freeform_policy(&req, map, maybe_car_and_target_queue) + } else if let Some(ref signal) = map.maybe_get_traffic_signal(state.id) { state.traffic_signal_policy(signal, &req, speed, now, maybe_car_and_target_queue, map) } else if let Some(ref sign) = map.maybe_get_stop_sign(state.id) { state.stop_sign_policy(sign, &req, now, map, scheduler, maybe_car_and_target_queue) } else { - // TODO This never gets called right now - state.freeform_policy(&req, map, maybe_car_and_target_queue) + unreachable!() }; if allowed { @@ -186,8 +193,7 @@ impl State { map: &Map, maybe_car_and_target_queue: Option<(&mut Queue, &Car)>, ) -> bool { - // Allow concurrent turns that don't conflict, don't prevent target lane from spilling - // over. + // Allow concurrent turns that don't conflict if self.any_accepted_conflict_with(req.turn, map) { return false; } diff --git a/sim/src/sim.rs b/sim/src/sim.rs index 419c12a833..a81a379cec 100644 --- a/sim/src/sim.rs +++ b/sim/src/sim.rs @@ -52,22 +52,43 @@ pub struct Sim { events_since_last_step: Vec, } +#[derive(Clone)] +pub struct SimOptions { + pub run_name: String, + pub savestate_every: Option, + pub use_freeform_policy_everywhere: bool, +} + +impl SimOptions { + pub fn new(run_name: &str) -> SimOptions { + SimOptions { + run_name: run_name.to_string(), + savestate_every: None, + use_freeform_policy_everywhere: false, + } + } +} + // Setup impl Sim { - pub fn new(map: &Map, run_name: String, savestate_every: Option) -> Sim { + pub fn new(map: &Map, opts: SimOptions) -> Sim { let mut scheduler = Scheduler::new(); // TODO Gridlock detection doesn't add value right now. if false { scheduler.push(CHECK_FOR_GRIDLOCK_FREQUENCY, Command::CheckForGridlock); } - if let Some(d) = savestate_every { + if let Some(d) = opts.savestate_every { scheduler.push(d, Command::Savestate(d)); } Sim { driving: DrivingSimState::new(map), parking: ParkingSimState::new(map), walking: WalkingSimState::new(), - intersections: IntersectionSimState::new(map, &mut scheduler), + intersections: IntersectionSimState::new( + map, + &mut scheduler, + opts.use_freeform_policy_everywhere, + ), transit: TransitSimState::new(), trips: TripManager::new(), spawner: TripSpawner::new(), @@ -79,7 +100,7 @@ impl Sim { map_name: map.get_name().to_string(), // TODO edits_name: "no_edits".to_string(), - run_name, + run_name: opts.run_name, step_count: 0, trip_positions: None, events_since_last_step: Vec::new(), diff --git a/tests/src/sim_determinism.rs b/tests/src/sim_determinism.rs index ca2164e4b3..faba809450 100644 --- a/tests/src/sim_determinism.rs +++ b/tests/src/sim_determinism.rs @@ -1,7 +1,7 @@ use crate::runner::TestRunner; use abstutil::Timer; use geom::Duration; -use sim::{Scenario, Sim, SimFlags}; +use sim::{Scenario, Sim, SimFlags, SimOptions}; pub fn run(t: &mut TestRunner) { t.run_slow("serialization", |_| { @@ -19,7 +19,7 @@ pub fn run(t: &mut TestRunner) { println!("Creating two simulations"); let flags = SimFlags::for_test("from_scratch_1"); let (map, mut sim1, _) = flags.load(None, &mut Timer::throwaway()); - let mut sim2 = Sim::new(&map, "from_scratch_2".to_string(), None); + let mut sim2 = Sim::new(&map, SimOptions::new("from_scratch_2")); Scenario::small_run(&map).instantiate( &mut sim1, &map, @@ -52,7 +52,7 @@ pub fn run(t: &mut TestRunner) { println!("Creating two simulations"); let flags = SimFlags::for_test("with_savestating_1"); let (map, mut sim1, _) = flags.load(None, &mut Timer::throwaway()); - let mut sim2 = Sim::new(&map, "with_savestating_2".to_string(), None); + let mut sim2 = Sim::new(&map, SimOptions::new("with_savestating_2")); Scenario::small_run(&map).instantiate( &mut sim1, &map,