mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-25 11:44:25 +03:00
writing savestates in a consistent place
This commit is contained in:
parent
6eb935a88d
commit
269235d1e1
3
.gitignore
vendored
3
.gitignore
vendored
@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
editor/editor_state
|
editor/editor_state
|
||||||
editor/road_edits.json
|
editor/road_edits.json
|
||||||
editor/sim_state
|
|
||||||
headless/sim_state
|
|
||||||
data/*.abst
|
data/*.abst
|
||||||
data/input/*
|
data/input/*
|
||||||
|
data/save/*
|
||||||
|
@ -604,3 +604,25 @@ SidewalkSpot
|
|||||||
## Stop sign priority
|
## Stop sign priority
|
||||||
|
|
||||||
Use OSM highway tags to rank. For all the turns on the higher priority road, detect priority/yield based on turn angle, I guess.
|
Use OSM highway tags to rank. For all the turns on the higher priority road, detect priority/yield based on turn angle, I guess.
|
||||||
|
|
||||||
|
## Watch tests easily
|
||||||
|
|
||||||
|
- need to organize savestate captures
|
||||||
|
- dedicated place: data/savestates/MAP/scenario/time
|
||||||
|
- plumb map name, scenario name
|
||||||
|
- should be able to just point to one of these saves, not refer to the map or RNG seed again
|
||||||
|
- also kinda needed for time traveling later
|
||||||
|
|
||||||
|
- when a problem happens, we want to back up a little bit
|
||||||
|
- probably just need automatic occasional savestating, and to print a nice command to rerun from it
|
||||||
|
|
||||||
|
## Diffing for A/B tests
|
||||||
|
|
||||||
|
Basic problem: how do we show map edits/diffs?
|
||||||
|
- could be useful for debugging as new data sources come in
|
||||||
|
- and is vital part of the game
|
||||||
|
- UI
|
||||||
|
- highlight edited things
|
||||||
|
- hold a button to show the original versions of things in a transparentish overlay
|
||||||
|
|
||||||
|
How to show diffs for agents?
|
||||||
|
@ -3,3 +3,4 @@
|
|||||||
## Groups that may be eventually interested
|
## Groups that may be eventually interested
|
||||||
|
|
||||||
- Seattle Times Traffic Lab
|
- Seattle Times Traffic Lab
|
||||||
|
- https://www.citylab.com/transportation/2018/08/is-it-time-to-rethink-what-a-bike-lane-is/568483/
|
||||||
|
@ -65,6 +65,10 @@ struct Flags {
|
|||||||
/// Optional savestate to load
|
/// Optional savestate to load
|
||||||
#[structopt(long = "load_from")]
|
#[structopt(long = "load_from")]
|
||||||
load_from: Option<String>,
|
load_from: Option<String>,
|
||||||
|
|
||||||
|
/// Scenario name for savestating
|
||||||
|
#[structopt(long = "scenario_name", default_value = "editor")]
|
||||||
|
scenario_name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@ -106,6 +110,7 @@ fn main() {
|
|||||||
glyphs,
|
glyphs,
|
||||||
ui::UI::new(
|
ui::UI::new(
|
||||||
&flags.abst_input,
|
&flags.abst_input,
|
||||||
|
flags.scenario_name,
|
||||||
window_size,
|
window_size,
|
||||||
flags.rng_seed,
|
flags.rng_seed,
|
||||||
flags.kml,
|
flags.kml,
|
||||||
|
@ -21,9 +21,9 @@ pub struct SimController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SimController {
|
impl SimController {
|
||||||
pub fn new(map: &Map, rng_seed: Option<u8>) -> SimController {
|
pub fn new(map: &Map, scenario_name: String, rng_seed: Option<u8>) -> SimController {
|
||||||
SimController {
|
SimController {
|
||||||
sim: Sim::new(map, rng_seed),
|
sim: Sim::new(map, scenario_name, rng_seed),
|
||||||
desired_speed: 1.0,
|
desired_speed: 1.0,
|
||||||
last_step: None,
|
last_step: None,
|
||||||
benchmark: None,
|
benchmark: None,
|
||||||
@ -41,8 +41,7 @@ impl SimController {
|
|||||||
self.desired_speed += ADJUST_SPEED;
|
self.desired_speed += ADJUST_SPEED;
|
||||||
}
|
}
|
||||||
if input.unimportant_key_pressed(Key::O, "save sim state") {
|
if input.unimportant_key_pressed(Key::O, "save sim state") {
|
||||||
abstutil::write_json("sim_state", &self.sim).expect("Writing sim state failed");
|
self.sim.save();
|
||||||
println!("Wrote sim_state");
|
|
||||||
}
|
}
|
||||||
if input.unimportant_key_pressed(Key::P, "load sim state") {
|
if input.unimportant_key_pressed(Key::P, "load sim state") {
|
||||||
self.sim = abstutil::read_json("sim_state").expect("sim state failed");
|
self.sim = abstutil::read_json("sim_state").expect("sim state failed");
|
||||||
|
@ -81,6 +81,7 @@ pub struct UI {
|
|||||||
impl UI {
|
impl UI {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
abst_path: &str,
|
abst_path: &str,
|
||||||
|
scenario_name: String,
|
||||||
window_size: Size,
|
window_size: Size,
|
||||||
rng_seed: Option<u8>,
|
rng_seed: Option<u8>,
|
||||||
kml: Option<String>,
|
kml: Option<String>,
|
||||||
@ -102,7 +103,7 @@ impl UI {
|
|||||||
|
|
||||||
let steepness_viz = SteepnessVisualizer::new(&map);
|
let steepness_viz = SteepnessVisualizer::new(&map);
|
||||||
let turn_colors = TurnColors::new(&control_map);
|
let turn_colors = TurnColors::new(&control_map);
|
||||||
let mut sim_ctrl = SimController::new(&map, rng_seed);
|
let mut sim_ctrl = SimController::new(&map, scenario_name, rng_seed);
|
||||||
if let Some(path) = load_sim_from {
|
if let Some(path) = load_sim_from {
|
||||||
sim_ctrl.sim = abstutil::read_json(&path).expect("loading sim state failed");
|
sim_ctrl.sim = abstutil::read_json(&path).expect("loading sim state failed");
|
||||||
println!("Loaded {}", path);
|
println!("Loaded {}", path);
|
||||||
|
@ -31,6 +31,10 @@ struct Flags {
|
|||||||
/// Big or large random scenario?
|
/// Big or large random scenario?
|
||||||
#[structopt(long = "big_sim")]
|
#[structopt(long = "big_sim")]
|
||||||
big_sim: bool,
|
big_sim: bool,
|
||||||
|
|
||||||
|
/// Scenario name for savestating
|
||||||
|
#[structopt(long = "scenario_name", default_value = "editor")]
|
||||||
|
scenario_name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@ -41,7 +45,7 @@ fn main() {
|
|||||||
.expect("Couldn't load map");
|
.expect("Couldn't load map");
|
||||||
// TODO could load savestate
|
// TODO could load savestate
|
||||||
let control_map = control::ControlMap::new(&map);
|
let control_map = control::ControlMap::new(&map);
|
||||||
let mut sim = sim::Sim::new(&map, flags.rng_seed);
|
let mut sim = sim::Sim::new(&map, flags.scenario_name, flags.rng_seed);
|
||||||
|
|
||||||
if let Some(path) = flags.load_from {
|
if let Some(path) = flags.load_from {
|
||||||
sim = abstutil::read_json(&path).expect("loading sim state failed");
|
sim = abstutil::read_json(&path).expect("loading sim state failed");
|
||||||
@ -77,8 +81,7 @@ fn main() {
|
|||||||
println!("{0}, speed = {1:.2}x", sim.summary(), speed);
|
println!("{0}, speed = {1:.2}x", sim.summary(), speed);
|
||||||
}
|
}
|
||||||
if Some(sim.time) == save_at {
|
if Some(sim.time) == save_at {
|
||||||
abstutil::write_json("sim_state", &sim).expect("Writing sim state failed");
|
sim.save();
|
||||||
println!("Wrote sim_state at {}", sim.time);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ use raw_data;
|
|||||||
use road::{Road, RoadID};
|
use road::{Road, RoadID};
|
||||||
use std::collections::{BTreeMap, HashMap};
|
use std::collections::{BTreeMap, HashMap};
|
||||||
use std::io::Error;
|
use std::io::Error;
|
||||||
|
use std::path;
|
||||||
use turn::{Turn, TurnID};
|
use turn::{Turn, TurnID};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
@ -26,17 +27,29 @@ pub struct Map {
|
|||||||
|
|
||||||
// TODO maybe dont need to retain GPS stuff later
|
// TODO maybe dont need to retain GPS stuff later
|
||||||
bounds: Bounds,
|
bounds: Bounds,
|
||||||
|
|
||||||
|
name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Map {
|
impl Map {
|
||||||
pub fn new(path: &str, edits: &Edits) -> Result<Map, Error> {
|
pub fn new(path: &str, edits: &Edits) -> Result<Map, Error> {
|
||||||
let data: raw_data::Map = abstutil::read_binary(path)?;
|
let data: raw_data::Map = abstutil::read_binary(path)?;
|
||||||
Ok(Map::create_from_raw(data, edits))
|
Ok(Map::create_from_raw(
|
||||||
|
path::Path::new(path)
|
||||||
|
.file_stem()
|
||||||
|
.unwrap()
|
||||||
|
.to_os_string()
|
||||||
|
.into_string()
|
||||||
|
.unwrap(),
|
||||||
|
data,
|
||||||
|
edits,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_from_raw(data: raw_data::Map, edits: &Edits) -> Map {
|
pub fn create_from_raw(name: String, data: raw_data::Map, edits: &Edits) -> Map {
|
||||||
let bounds = data.get_gps_bounds();
|
let bounds = data.get_gps_bounds();
|
||||||
let mut m = Map {
|
let mut m = Map {
|
||||||
|
name,
|
||||||
bounds,
|
bounds,
|
||||||
roads: Vec::new(),
|
roads: Vec::new(),
|
||||||
lanes: Vec::new(),
|
lanes: Vec::new(),
|
||||||
@ -339,4 +352,8 @@ impl Map {
|
|||||||
pub fn get_driving_lane_from_parking(&self, parking: LaneID) -> Option<LaneID> {
|
pub fn get_driving_lane_from_parking(&self, parking: LaneID) -> Option<LaneID> {
|
||||||
self.get_parent(parking).find_driving_lane(parking)
|
self.get_parent(parking).find_driving_lane(parking)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_name(&self) -> &String {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,6 +126,30 @@ impl Tick {
|
|||||||
pub fn is_multiple_of_minute(&self) -> bool {
|
pub fn is_multiple_of_minute(&self) -> bool {
|
||||||
self.0 % 600 == 0
|
self.0 % 600 == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_parts(&self) -> (u32, u32, u32, u32) {
|
||||||
|
// TODO hardcoding these to avoid floating point issues... urgh. :\
|
||||||
|
let ticks_per_second = 10;
|
||||||
|
let ticks_per_minute = 60 * ticks_per_second;
|
||||||
|
let ticks_per_hour = 60 * ticks_per_minute;
|
||||||
|
|
||||||
|
let hours = self.0 / ticks_per_hour;
|
||||||
|
let mut remainder = self.0 % ticks_per_hour;
|
||||||
|
let minutes = remainder / ticks_per_minute;
|
||||||
|
remainder = remainder % ticks_per_minute;
|
||||||
|
let seconds = remainder / ticks_per_second;
|
||||||
|
remainder = remainder % ticks_per_second;
|
||||||
|
|
||||||
|
(hours, minutes, seconds, remainder)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_filename(&self) -> String {
|
||||||
|
let (hours, minutes, seconds, remainder) = self.get_parts();
|
||||||
|
format!(
|
||||||
|
"{0:02}h{1:02}m{2:02}.{3}s",
|
||||||
|
hours, minutes, seconds, remainder
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::ops::Add<Time> for Tick {
|
impl std::ops::Add<Time> for Tick {
|
||||||
@ -148,18 +172,7 @@ impl std::ops::Sub for Tick {
|
|||||||
|
|
||||||
impl std::fmt::Display for Tick {
|
impl std::fmt::Display for Tick {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
// TODO hardcoding these to avoid floating point issues... urgh. :\
|
let (hours, minutes, seconds, remainder) = self.get_parts();
|
||||||
let ticks_per_second = 10;
|
|
||||||
let ticks_per_minute = 60 * ticks_per_second;
|
|
||||||
let ticks_per_hour = 60 * ticks_per_minute;
|
|
||||||
|
|
||||||
let hours = self.0 / ticks_per_hour;
|
|
||||||
let mut remainder = self.0 % ticks_per_hour;
|
|
||||||
let minutes = remainder / ticks_per_minute;
|
|
||||||
remainder = remainder % ticks_per_minute;
|
|
||||||
let seconds = remainder / ticks_per_second;
|
|
||||||
remainder = remainder % ticks_per_second;
|
|
||||||
|
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{0:02}:{1:02}:{2:02}.{3}",
|
"{0:02}:{1:02}:{2:02}.{3}",
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
// Copyright 2018 Google LLC, licensed under http://www.apache.org/licenses/LICENSE-2.0
|
// Copyright 2018 Google LLC, licensed under http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
use abstutil;
|
||||||
use control::ControlMap;
|
use control::ControlMap;
|
||||||
use dimensioned::si;
|
use dimensioned::si;
|
||||||
use draw_car::DrawCar;
|
use draw_car::DrawCar;
|
||||||
@ -11,6 +12,7 @@ use map_model::{IntersectionID, LaneID, LaneType, Map, Turn, TurnID};
|
|||||||
use parking::ParkingSimState;
|
use parking::ParkingSimState;
|
||||||
use rand::{FromEntropy, SeedableRng, XorShiftRng};
|
use rand::{FromEntropy, SeedableRng, XorShiftRng};
|
||||||
use spawn::Spawner;
|
use spawn::Spawner;
|
||||||
|
use std;
|
||||||
use std::collections::{BTreeMap, HashMap, HashSet};
|
use std::collections::{BTreeMap, HashMap, HashSet};
|
||||||
use std::f64;
|
use std::f64;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
@ -25,6 +27,8 @@ pub struct Sim {
|
|||||||
#[derivative(PartialEq = "ignore")]
|
#[derivative(PartialEq = "ignore")]
|
||||||
rng: XorShiftRng,
|
rng: XorShiftRng,
|
||||||
pub time: Tick,
|
pub time: Tick,
|
||||||
|
map_name: String,
|
||||||
|
scenario_name: String,
|
||||||
|
|
||||||
spawner: Spawner,
|
spawner: Spawner,
|
||||||
intersection_state: IntersectionSimState,
|
intersection_state: IntersectionSimState,
|
||||||
@ -36,7 +40,7 @@ pub struct Sim {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Sim {
|
impl Sim {
|
||||||
pub fn new(map: &Map, rng_seed: Option<u8>) -> Sim {
|
pub fn new(map: &Map, scenario_name: String, rng_seed: Option<u8>) -> Sim {
|
||||||
let mut rng = XorShiftRng::from_entropy();
|
let mut rng = XorShiftRng::from_entropy();
|
||||||
if let Some(seed) = rng_seed {
|
if let Some(seed) = rng_seed {
|
||||||
rng = XorShiftRng::from_seed([seed; 16]);
|
rng = XorShiftRng::from_seed([seed; 16]);
|
||||||
@ -50,6 +54,8 @@ impl Sim {
|
|||||||
parking_state: ParkingSimState::new(map),
|
parking_state: ParkingSimState::new(map),
|
||||||
walking_state: WalkingSimState::new(),
|
walking_state: WalkingSimState::new(),
|
||||||
time: Tick::zero(),
|
time: Tick::zero(),
|
||||||
|
map_name: map.get_name().to_string(),
|
||||||
|
scenario_name,
|
||||||
car_properties: BTreeMap::new(),
|
car_properties: BTreeMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -306,6 +312,22 @@ impl Sim {
|
|||||||
pub fn debug_intersection(&mut self, id: IntersectionID, control_map: &ControlMap) {
|
pub fn debug_intersection(&mut self, id: IntersectionID, control_map: &ControlMap) {
|
||||||
self.intersection_state.debug(id, control_map);
|
self.intersection_state.debug(id, control_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn save(&self) -> String {
|
||||||
|
// If we wanted to be even more reproducible, we'd encode RNG seed, version of code, etc,
|
||||||
|
// but that's overkill right now.
|
||||||
|
let path = format!(
|
||||||
|
"../data/save/{}/{}/{}",
|
||||||
|
self.map_name,
|
||||||
|
self.scenario_name,
|
||||||
|
self.time.as_filename()
|
||||||
|
);
|
||||||
|
std::fs::create_dir_all(std::path::Path::new(&path).parent().unwrap())
|
||||||
|
.expect("Creating parent dir failed");
|
||||||
|
abstutil::write_json(&path, &self).expect("Writing sim state failed");
|
||||||
|
println!("Saved to {}", path);
|
||||||
|
path
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Benchmark {
|
pub struct Benchmark {
|
||||||
|
@ -13,7 +13,8 @@ fn aorta_model_completes() {
|
|||||||
let map = map_model::Map::new(input, &map_model::Edits::new()).expect("Couldn't load map");
|
let map = map_model::Map::new(input, &map_model::Edits::new()).expect("Couldn't load map");
|
||||||
let control_map = control::ControlMap::new(&map);
|
let control_map = control::ControlMap::new(&map);
|
||||||
|
|
||||||
let mut sim = sim::Sim::new(&map, Some(rng_seed));
|
// TODO need https://github.com/rust-lang/rfcs/issues/1743 to be less repetitive :(
|
||||||
|
let mut sim = sim::Sim::new(&map, "aorta_model_completes".to_string(), Some(rng_seed));
|
||||||
sim.seed_parked_cars(0.5);
|
sim.seed_parked_cars(0.5);
|
||||||
sim.seed_walking_trips(&map, spawn_count);
|
sim.seed_walking_trips(&map, spawn_count);
|
||||||
sim.seed_driving_trips(&map, spawn_count);
|
sim.seed_driving_trips(&map, spawn_count);
|
||||||
|
@ -12,7 +12,7 @@ fn serialization() {
|
|||||||
|
|
||||||
let map = map_model::Map::new(input, &map_model::Edits::new()).expect("Couldn't load map");
|
let map = map_model::Map::new(input, &map_model::Edits::new()).expect("Couldn't load map");
|
||||||
|
|
||||||
let mut sim = sim::Sim::new(&map, Some(rng_seed));
|
let mut sim = sim::Sim::new(&map, "serialization".to_string(), Some(rng_seed));
|
||||||
sim.seed_parked_cars(0.5);
|
sim.seed_parked_cars(0.5);
|
||||||
sim.seed_walking_trips(&map, spawn_count);
|
sim.seed_walking_trips(&map, spawn_count);
|
||||||
sim.seed_driving_trips(&map, spawn_count);
|
sim.seed_driving_trips(&map, spawn_count);
|
||||||
@ -34,8 +34,8 @@ fn from_scratch() {
|
|||||||
let map = map_model::Map::new(input, &map_model::Edits::new()).expect("Couldn't load map");
|
let map = map_model::Map::new(input, &map_model::Edits::new()).expect("Couldn't load map");
|
||||||
let control_map = control::ControlMap::new(&map);
|
let control_map = control::ControlMap::new(&map);
|
||||||
|
|
||||||
let mut sim1 = sim::Sim::new(&map, Some(rng_seed));
|
let mut sim1 = sim::Sim::new(&map, "from_scratch_1".to_string(), Some(rng_seed));
|
||||||
let mut sim2 = sim::Sim::new(&map, Some(rng_seed));
|
let mut sim2 = sim::Sim::new(&map, "from_scratch_2".to_string(), Some(rng_seed));
|
||||||
sim1.seed_parked_cars(0.5);
|
sim1.seed_parked_cars(0.5);
|
||||||
sim1.seed_walking_trips(&map, spawn_count);
|
sim1.seed_walking_trips(&map, spawn_count);
|
||||||
sim1.seed_driving_trips(&map, spawn_count);
|
sim1.seed_driving_trips(&map, spawn_count);
|
||||||
@ -45,13 +45,11 @@ fn from_scratch() {
|
|||||||
|
|
||||||
for _ in 1..600 {
|
for _ in 1..600 {
|
||||||
if sim1 != sim2 {
|
if sim1 != sim2 {
|
||||||
// TODO write to temporary files somewhere
|
|
||||||
// TODO need to sort dicts in json output to compare
|
// TODO need to sort dicts in json output to compare
|
||||||
abstutil::write_json("sim1_state.json", &sim1).unwrap();
|
|
||||||
abstutil::write_json("sim2_state.json", &sim2).unwrap();
|
|
||||||
panic!(
|
panic!(
|
||||||
"sim state differs at {}. compare sim1_state.json and sim2_state.json",
|
"sim state differs between {} and {}",
|
||||||
sim1.time
|
sim1.save(),
|
||||||
|
sim2.save()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
sim1.step(&map, &control_map);
|
sim1.step(&map, &control_map);
|
||||||
@ -70,8 +68,8 @@ fn with_savestating() {
|
|||||||
let map = map_model::Map::new(input, &map_model::Edits::new()).expect("Couldn't load map");
|
let map = map_model::Map::new(input, &map_model::Edits::new()).expect("Couldn't load map");
|
||||||
let control_map = control::ControlMap::new(&map);
|
let control_map = control::ControlMap::new(&map);
|
||||||
|
|
||||||
let mut sim1 = sim::Sim::new(&map, Some(rng_seed));
|
let mut sim1 = sim::Sim::new(&map, "with_savestating_1".to_string(), Some(rng_seed));
|
||||||
let mut sim2 = sim::Sim::new(&map, Some(rng_seed));
|
let mut sim2 = sim::Sim::new(&map, "with_savestating_2".to_string(), Some(rng_seed));
|
||||||
sim1.seed_parked_cars(0.5);
|
sim1.seed_parked_cars(0.5);
|
||||||
sim1.seed_walking_trips(&map, spawn_count);
|
sim1.seed_walking_trips(&map, spawn_count);
|
||||||
sim1.seed_driving_trips(&map, spawn_count);
|
sim1.seed_driving_trips(&map, spawn_count);
|
||||||
@ -85,38 +83,35 @@ fn with_savestating() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if sim1 != sim2 {
|
if sim1 != sim2 {
|
||||||
abstutil::write_json("sim1_state.json", &sim1).unwrap();
|
|
||||||
abstutil::write_json("sim2_state.json", &sim2).unwrap();
|
|
||||||
panic!(
|
panic!(
|
||||||
"sim state differs at {}. compare sim1_state.json and sim2_state.json",
|
"sim state differs between {} and {}",
|
||||||
sim1.time
|
sim1.save(),
|
||||||
|
sim2.save()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
abstutil::write_json("sim1_savestate.json", &sim1).unwrap();
|
let sim1_save = sim1.save();
|
||||||
|
|
||||||
for _ in 1..60 {
|
for _ in 1..60 {
|
||||||
sim1.step(&map, &control_map);
|
sim1.step(&map, &control_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
if sim1 == sim2 {
|
if sim1 == sim2 {
|
||||||
abstutil::write_json("sim1_state.json", &sim1).unwrap();
|
|
||||||
abstutil::write_json("sim2_state.json", &sim2).unwrap();
|
|
||||||
panic!(
|
panic!(
|
||||||
"sim state unexpectedly the same at {}. compare sim1_state.json and sim2_state.json",
|
"sim state unexpectly the same -- {} and {}",
|
||||||
sim1.time
|
sim1.save(),
|
||||||
|
sim2.save()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let sim3: sim::Sim = abstutil::read_json("sim1_savestate.json").unwrap();
|
let sim3: sim::Sim = abstutil::read_json(&sim1_save).unwrap();
|
||||||
if sim3 != sim2 {
|
if sim3 != sim2 {
|
||||||
abstutil::write_json("sim3_state.json", &sim3).unwrap();
|
|
||||||
abstutil::write_json("sim2_state.json", &sim2).unwrap();
|
|
||||||
panic!(
|
panic!(
|
||||||
"sim state differs at {}. compare sim3_state.json and sim2_state.json",
|
"sim state differs between {} and {}",
|
||||||
sim1.time
|
sim3.save(),
|
||||||
|
sim2.save()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::fs::remove_file("sim1_savestate.json").unwrap();
|
std::fs::remove_file(sim1_save).unwrap();
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ use map_model::LaneID;
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn park_on_goal_st() {
|
fn park_on_goal_st() {
|
||||||
let (map, control_map, mut sim) = setup(make_test_map());
|
let (map, control_map, mut sim) = setup("park_on_goal_st", make_test_map());
|
||||||
let (parking1, parking2, driving2) = (LaneID(1), LaneID(4), LaneID(3));
|
let (parking1, parking2, driving2) = (LaneID(1), LaneID(4), LaneID(3));
|
||||||
|
|
||||||
assert_eq!(map.get_l(parking1).number_parking_spots(), 8);
|
assert_eq!(map.get_l(parking1).number_parking_spots(), 8);
|
||||||
@ -37,7 +37,7 @@ fn park_on_goal_st() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn wander_around_for_parking() {
|
fn wander_around_for_parking() {
|
||||||
let (map, control_map, mut sim) = setup(make_test_map());
|
let (map, control_map, mut sim) = setup("wander_around_for_parking", make_test_map());
|
||||||
let (parking1, parking2, driving2) = (LaneID(1), LaneID(4), LaneID(3));
|
let (parking1, parking2, driving2) = (LaneID(1), LaneID(4), LaneID(3));
|
||||||
|
|
||||||
assert_eq!(map.get_l(parking1).number_parking_spots(), 8);
|
assert_eq!(map.get_l(parking1).number_parking_spots(), 8);
|
||||||
@ -63,10 +63,13 @@ fn wander_around_for_parking() {
|
|||||||
println!("Expected conditions met at {}", sim.time);
|
println!("Expected conditions met at {}", sim.time);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup(map: map_model::Map) -> (map_model::Map, control::ControlMap, sim::Sim) {
|
fn setup(
|
||||||
|
scenario_name: &str,
|
||||||
|
map: map_model::Map,
|
||||||
|
) -> (map_model::Map, control::ControlMap, sim::Sim) {
|
||||||
let rng_seed = 123;
|
let rng_seed = 123;
|
||||||
let control_map = control::ControlMap::new(&map);
|
let control_map = control::ControlMap::new(&map);
|
||||||
let sim = sim::Sim::new(&map, Some(rng_seed));
|
let sim = sim::Sim::new(&map, scenario_name.to_string(), Some(rng_seed));
|
||||||
(map, control_map, sim)
|
(map, control_map, sim)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,6 +86,7 @@ fn make_test_map() -> map_model::Map {
|
|||||||
let south_pts = triangle_around(150.0, 90.0);
|
let south_pts = triangle_around(150.0, 90.0);
|
||||||
|
|
||||||
let map = map_model::Map::create_from_raw(
|
let map = map_model::Map::create_from_raw(
|
||||||
|
"test_map".to_string(),
|
||||||
raw_data::Map {
|
raw_data::Map {
|
||||||
roads: vec![raw_data::Road {
|
roads: vec![raw_data::Road {
|
||||||
points: vec![left, right],
|
points: vec![left, right],
|
||||||
|
Loading…
Reference in New Issue
Block a user