tiny tweaks from final testing:

- cutscene wording
- elide traffic tab on parking lanes
- dont crash when traffic signal data needs fixing, just warn more
loudly. this lets lanes near some signals actually be modified
This commit is contained in:
Dustin Carlino 2020-06-21 11:38:34 -07:00
parent 506077a7b7
commit eedf80bfef
9 changed files with 49 additions and 16 deletions

View File

@ -26,6 +26,7 @@ Measure the effects:
## Documentation
- [How A/B Street works](docs/how_it_works.md)
- [Case studies](https://dabreegster.github.io/abstreet/)
- Technical
- [Developer guide](docs/dev.md)
- [Map model](docs/articles/map/article.md)

View File

@ -108,6 +108,7 @@ pub struct Timer<'a> {
notes: Vec<String>,
pub(crate) warnings: Vec<String>,
pub(crate) errors: Vec<String>,
sink: Option<Box<dyn TimerSink + 'a>>,
}
@ -128,6 +129,7 @@ impl<'a> Timer<'a> {
outermost_name: name.clone(),
notes: Vec::new(),
warnings: Vec::new(),
errors: Vec::new(),
sink: None,
};
t.start(name);
@ -180,6 +182,10 @@ impl<'a> Timer<'a> {
self.warnings.push(line);
}
pub fn error(&mut self, line: String) {
self.errors.push(line);
}
// Used to end the scope of a timer early.
pub fn done(self) {}
@ -421,6 +427,14 @@ impl<'a> std::ops::Drop for Timer<'a> {
self.println(String::new());
}
if !self.errors.is_empty() {
self.println(format!("***** {} errors: *****", self.errors.len()));
for line in &self.errors {
Timer::selfless_println(&mut self.sink, line.to_string());
}
self.println(String::new());
}
// In case of lots of notes and warnings, repeat the overall timing.
Timer::selfless_println(&mut self.sink, self.results[0].clone());
}

View File

@ -1,4 +1,4 @@
# A/B Street
# Case studies
See [the main page](https://github.com/dabreegster/abstreet/) for now. I'll
probably organize everything here eventually.

View File

@ -608,7 +608,12 @@ fn find_bad_signals(app: &App) {
println!("Bad traffic signals:");
for i in app.primary.map.all_intersections() {
if i.is_traffic_signal() {
let first = &ControlTrafficSignal::get_possible_policies(&app.primary.map, i.id)[0].0;
let first = &ControlTrafficSignal::get_possible_policies(
&app.primary.map,
i.id,
&mut Timer::throwaway(),
)[0]
.0;
if first == "phase per road" || first == "arbitrary assignment" {
println!("- {}", i.id);
ControlTrafficSignal::brute_force(&app.primary.map, i.id);

View File

@ -533,6 +533,7 @@ fn edit_entire_signal(app: &App, i: IntersectionID, mode: GameplayMode) -> Box<d
Choice::from(ControlTrafficSignal::get_possible_policies(
&app.primary.map,
i,
&mut Timer::throwaway(),
))
})?;
Some(Transition::PopWithData(Box::new(move |state, ctx, app| {
@ -596,10 +597,13 @@ fn edit_entire_signal(app: &App, i: IntersectionID, mode: GameplayMode) -> Box<d
Some(Transition::PopWithData(Box::new(move |state, ctx, app| {
let editor = state.downcast_mut::<TrafficSignalEditor>().unwrap();
let orig_signal = app.primary.map.get_traffic_signal(editor.i);
let new_signal =
ControlTrafficSignal::get_possible_policies(&app.primary.map, editor.i)
.remove(0)
.1;
let new_signal = ControlTrafficSignal::get_possible_policies(
&app.primary.map,
editor.i,
&mut Timer::throwaway(),
)
.remove(0)
.1;
editor.command_stack.push(orig_signal.clone());
editor.redo_stack.clear();
editor.top_panel = make_top_panel(ctx, app, true, false);

View File

@ -217,10 +217,10 @@ fn header(ctx: &EventCtx, app: &App, details: &mut Details, id: LaneID, tab: Tab
]));
rows.push(format!("@ {}", r.get_name()).draw_text(ctx));
let mut tabs = vec![
("Info", Tab::LaneInfo(id)),
("Traffic", Tab::LaneTraffic(id, DataOptions::new())),
];
let mut tabs = vec![("Info", Tab::LaneInfo(id))];
if !l.is_parking() {
tabs.push(("Traffic", Tab::LaneTraffic(id, DataOptions::new())));
}
if app.opts.dev {
tabs.push(("Debug", Tab::LaneDebug(id)));
}

View File

@ -1427,7 +1427,10 @@ fn intro_story(ctx: &mut EventCtx, app: &App) -> Box<dyn State> {
.boss("Light rail and robot cars aren't here to save the day! Know what you'll be using?")
.extra("drone", "The traffic drone")
.player("Is that... duct tape?")
.boss("We ran out of spit and prayers. Well, off to training for you!")
.boss(
"Can't spit anymore cause of COVID and don't get me started on prayers. Well, off to \
training for you!",
)
.build(
ctx,
app,

View File

@ -2,10 +2,15 @@ use crate::{
ControlTrafficSignal, IntersectionID, Map, Phase, RoadID, TurnGroup, TurnGroupID, TurnPriority,
TurnType,
};
use abstutil::Timer;
use geom::Duration;
use std::collections::BTreeMap;
pub fn get_possible_policies(map: &Map, id: IntersectionID) -> Vec<(String, ControlTrafficSignal)> {
pub fn get_possible_policies(
map: &Map,
id: IntersectionID,
timer: &mut Timer,
) -> Vec<(String, ControlTrafficSignal)> {
let mut results = Vec::new();
// TODO Cache with lazy_static. Don't serialize in Map; the repo of signal data may evolve
@ -17,10 +22,10 @@ pub fn get_possible_policies(map: &Map, id: IntersectionID) -> Vec<(String, Cont
if let Some(ts) = ControlTrafficSignal::import(raw, id, map) {
results.push(("hand-mapped current real settings".to_string(), ts));
} else {
panic!(
timer.error(format!(
"seattle_traffic_signals data for {} out of date, go update it",
map.get_i(id).orig_id.osm_node_id
);
));
}
}

View File

@ -29,7 +29,7 @@ pub struct Phase {
impl ControlTrafficSignal {
pub fn new(map: &Map, id: IntersectionID, timer: &mut Timer) -> ControlTrafficSignal {
let mut policies = ControlTrafficSignal::get_possible_policies(map, id);
let mut policies = ControlTrafficSignal::get_possible_policies(map, id, timer);
if policies.len() == 1 {
timer.warn(format!("Falling back to greedy_assignment for {}", id));
}
@ -39,8 +39,9 @@ impl ControlTrafficSignal {
pub fn get_possible_policies(
map: &Map,
id: IntersectionID,
timer: &mut Timer,
) -> Vec<(String, ControlTrafficSignal)> {
get_possible_policies(map, id)
get_possible_policies(map, id, timer)
}
// TODO tmp
pub fn brute_force(map: &Map, id: IntersectionID) {