1 use crate::{AlertHandler, Scenario, Sim, SimOptions};
2 use abstutil::CmdArgs;
3 use map_model::{Map, MapEdits};
4 use rand::SeedableRng;
5 use rand_xorshift::XorShiftRng;
6 
7 const RNG_SEED: u8 = 42;
8 
9 #[derive(Clone)]
10 pub struct SimFlags {
11     pub load: String,
12     pub rng_seed: u8,
13     pub opts: SimOptions,
14 }
15 
16 impl SimFlags {
from_args(args: &mut CmdArgs) -> SimFlags17     pub fn from_args(args: &mut CmdArgs) -> SimFlags {
18         let rng_seed = args
19             .optional_parse("--rng_seed", |s| s.parse())
20             .unwrap_or(RNG_SEED);
21 
22         SimFlags {
23             load: args
24                 .optional_free()
25                 .unwrap_or_else(|| abstutil::path_map("montlake")),
26             rng_seed,
27             opts: SimOptions {
28                 run_name: args
29                     .optional("--run_name")
30                     .unwrap_or_else(|| "unnamed".to_string()),
31                 use_freeform_policy_everywhere: args.enabled("--freeform_policy"),
32                 dont_block_the_box: !args.enabled("--disable_block_the_box"),
33                 recalc_lanechanging: !args.enabled("--disable_recalc_lc"),
34                 break_turn_conflict_cycles: !args.enabled("--disable_break_turn_conflict_cycles"),
35                 handle_uber_turns: !args.enabled("--disable_handle_uber_turns"),
36                 enable_pandemic_model: if args.enabled("--pandemic") {
37                     Some(XorShiftRng::from_seed([rng_seed; 16]))
38                 } else {
39                     None
40                 },
41                 alerts: args
42                     .optional("--alerts")
43                     .map(|x| match x.as_ref() {
44                         "print" => AlertHandler::Print,
45                         "block" => AlertHandler::Block,
46                         "silence" => AlertHandler::Silence,
47                         _ => panic!("Bad --alerts={}. Must be print|block|silence", x),
48                     })
49                     .unwrap_or(AlertHandler::Print),
50                 pathfinding_upfront: args.enabled("--pathfinding_upfront"),
51             },
52         }
53     }
54 
55     // TODO rename seattle_test
for_test(run_name: &str) -> SimFlags56     pub fn for_test(run_name: &str) -> SimFlags {
57         SimFlags::synthetic_test("montlake", run_name)
58     }
59 
synthetic_test(map: &str, run_name: &str) -> SimFlags60     pub fn synthetic_test(map: &str, run_name: &str) -> SimFlags {
61         SimFlags {
62             load: abstutil::path_map(map),
63             rng_seed: RNG_SEED,
64             opts: SimOptions::new(run_name),
65         }
66     }
67 
make_rng(&self) -> XorShiftRng68     pub fn make_rng(&self) -> XorShiftRng {
69         XorShiftRng::from_seed([self.rng_seed; 16])
70     }
71 
72     // Convenience method to setup everything.
load(&self, timer: &mut abstutil::Timer) -> (Map, Sim, XorShiftRng)73     pub fn load(&self, timer: &mut abstutil::Timer) -> (Map, Sim, XorShiftRng) {
74         let mut rng = self.make_rng();
75 
76         let mut opts = self.opts.clone();
77 
78         if self.load.starts_with(&abstutil::path("player/saves/")) {
79             timer.note(format!("Resuming from {}", self.load));
80 
81             let mut sim: Sim = abstutil::read_binary(self.load.clone(), timer);
82 
83             let mut map = Map::new(abstutil::path_map(&sim.map_name), timer);
84             if sim.edits_name != "untitled edits" {
85                 map.must_apply_edits(
86                     MapEdits::load(
87                         &map,
88                         abstutil::path_edits(map.get_name(), &sim.edits_name),
89                         timer,
90                     )
91                     .unwrap(),
92                     timer,
93                 );
94                 map.recalculate_pathfinding_after_edits(timer);
95             }
96             sim.restore_paths(&map, timer);
97 
98             (map, sim, rng)
99         } else if self.load.starts_with(&abstutil::path("system/scenarios/")) {
100             timer.note(format!(
101                 "Seeding the simulation from scenario {}",
102                 self.load
103             ));
104 
105             let scenario: Scenario = abstutil::read_binary(self.load.clone(), timer);
106 
107             let map = Map::new(abstutil::path_map(&scenario.map_name), timer);
108 
109             if opts.run_name == "unnamed" {
110                 opts.run_name = scenario.scenario_name.clone();
111             }
112             let mut sim = Sim::new(&map, opts, timer);
113             scenario.instantiate(&mut sim, &map, &mut rng, timer);
114 
115             (map, sim, rng)
116         } else if self.load.starts_with(&abstutil::path_all_raw_maps())
117             || self.load.starts_with(&abstutil::path_all_synthetic_maps())
118             || self.load.starts_with(&abstutil::path_all_maps())
119         {
120             timer.note(format!("Loading map {}", self.load));
121 
122             let map = Map::new(self.load.clone(), timer);
123 
124             timer.start("create sim");
125             let sim = Sim::new(&map, opts, timer);
126             timer.stop("create sim");
127 
128             (map, sim, rng)
129         } else {
130             panic!("Don't know how to load {}", self.load);
131         }
132     }
133 }
134