start wiring together a new challenge mode to optimize a single commute. (and delete an old challenge mode that's really unspecified and doesnt have any interesting code to preserve)

This commit is contained in:
Dustin Carlino 2020-04-08 17:47:00 -07:00
parent eb1ea20a37
commit ef2a237c5d
4 changed files with 124 additions and 149 deletions

View File

@ -6,7 +6,7 @@ use abstutil::Timer;
use ezgui::{hotkey, Btn, Color, Composite, EventCtx, Key, Line, Text, Widget};
use geom::{Duration, Time};
use map_model::Map;
use sim::{Scenario, Sim, SimFlags, SimOptions, TripMode};
use sim::{PersonID, Scenario, Sim, SimFlags, SimOptions};
use std::collections::{BTreeMap, HashSet};
// TODO Also have some kind of screenshot to display for each challenge
@ -53,6 +53,16 @@ pub fn all_challenges(dev: bool) -> BTreeMap<String, Vec<Challenge>> {
},
],
);
tree.insert(
"Optimize somebody's commute".to_string(),
vec![Challenge {
title: "Part 1".to_string(),
description: vec!["Speed up one person's daily commute".to_string()],
alias: "commute/pt1".to_string(),
gameplay: GameplayMode::OptimizeCommute(PersonID(3434)),
}],
);
if dev {
tree.insert(
"Speed up a bus route (WIP)".to_string(),
@ -92,33 +102,6 @@ pub fn all_challenges(dev: bool) -> BTreeMap<String, Vec<Challenge>> {
gameplay: GameplayMode::CreateGridlock(abstutil::path_map("montlake")),
}],
);
tree.insert(
"Playing favorites (WIP)".to_string(),
vec![
Challenge {
title: "Speed up all bike trips".to_string(),
description: vec![
"Reduce the 50%ile trip times of bikes by at least 1 minute".to_string()
],
alias: "fave/bike".to_string(),
gameplay: GameplayMode::FasterTrips(
abstutil::path_map("montlake"),
TripMode::Bike,
),
},
Challenge {
title: "Speed up all car trips".to_string(),
description: vec!["Reduce the 50%ile trip times of drivers by at least 5 \
minutes"
.to_string()],
alias: "fave/car".to_string(),
gameplay: GameplayMode::FasterTrips(
abstutil::path_map("montlake"),
TripMode::Drive,
),
},
],
);
}
tree
}

View File

@ -0,0 +1,108 @@
use crate::app::App;
use crate::game::Transition;
use crate::managed::{WrappedComposite, WrappedOutcome};
use crate::sandbox::gameplay::{challenge_controller, FinalScore, GameplayMode, GameplayState};
use crate::sandbox::{SandboxControls, SandboxMode};
use ezgui::{Btn, EventCtx, GfxCtx};
use geom::{Duration, Time};
use sim::PersonID;
const GOAL: Duration = Duration::const_seconds(3.0 * 60.0);
pub struct OptimizeCommute {
top_center: WrappedComposite,
person: PersonID,
time: Time,
}
impl OptimizeCommute {
pub fn new(ctx: &mut EventCtx, app: &App, person: PersonID) -> Box<dyn GameplayState> {
Box::new(OptimizeCommute {
top_center: make_top_center(ctx, app, person),
person,
time: Time::START_OF_DAY,
})
}
}
impl GameplayState for OptimizeCommute {
fn event(
&mut self,
ctx: &mut EventCtx,
app: &mut App,
_: &mut SandboxControls,
) -> (Option<Transition>, bool) {
if self.time != app.primary.sim.time() {
self.top_center = make_top_center(ctx, app, self.person);
self.time = app.primary.sim.time();
}
match self.top_center.event(ctx, app) {
Some(WrappedOutcome::Transition(t)) => {
return (Some(t), false);
}
Some(WrappedOutcome::Clicked(x)) => match x.as_ref() {
"locate person" => {
return (
Some(Transition::KeepWithData(Box::new(|state, app, ctx| {
let mode = state.downcast_mut::<SandboxMode>().unwrap();
let mut actions = mode.contextual_actions();
mode.controls.common.as_mut().unwrap().launch_info_panel(
// TODO
crate::helpers::ID::Building(map_model::BuildingID(123)),
ctx,
app,
&mut actions,
);
}))),
false,
);
}
_ => unreachable!(),
},
None => {}
}
// TODO After all of the person's trips are done, we can actually end then
if app.primary.sim.is_done() {
let (verdict, success) = final_score(app);
// TODO Plumb through a next stage here
let next = None;
return (
Some(Transition::Push(FinalScore::new(
ctx,
app,
verdict,
GameplayMode::OptimizeCommute(self.person),
next,
))),
false,
);
}
(None, false)
}
fn draw(&self, g: &mut GfxCtx, _: &App) {
self.top_center.draw(g);
}
}
fn make_top_center(ctx: &mut EventCtx, app: &App, person: PersonID) -> WrappedComposite {
let mut rows = vec![
Btn::svg_def("../data/system/assets/tools/location.svg").build(ctx, "locate person", None),
];
challenge_controller(
ctx,
app,
GameplayMode::OptimizeCommute(person),
&format!("Optimize {}'s commute", person),
rows,
)
}
// True if the challenge is completed
fn final_score(app: &App) -> (String, bool) {
(format!("TODO"), false)
}

View File

@ -1,112 +0,0 @@
use crate::app::App;
use crate::game::Transition;
use crate::helpers::{cmp_count_more, cmp_duration_shorter};
use crate::managed::{WrappedComposite, WrappedOutcome};
use crate::sandbox::gameplay::{challenge_controller, GameplayMode, GameplayState};
use crate::sandbox::SandboxControls;
use abstutil::prettyprint_usize;
use ezgui::{EventCtx, GfxCtx, Line, Text};
use geom::Statistic;
use sim::TripMode;
pub struct FasterTrips {
top_center: WrappedComposite,
}
impl FasterTrips {
pub fn new(
ctx: &mut EventCtx,
app: &App,
trip_mode: TripMode,
mode: GameplayMode,
) -> Box<dyn GameplayState> {
Box::new(FasterTrips {
top_center: challenge_controller(
ctx,
app,
mode,
&format!("Faster Trips {} Challenge", trip_mode.ongoing_verb()),
Vec::new(),
),
})
}
}
impl GameplayState for FasterTrips {
fn event(
&mut self,
ctx: &mut EventCtx,
app: &mut App,
_: &mut SandboxControls,
) -> (Option<Transition>, bool) {
match self.top_center.event(ctx, app) {
Some(WrappedOutcome::Transition(t)) => {
return (Some(t), false);
}
Some(WrappedOutcome::Clicked(_)) => unreachable!(),
None => {}
}
(None, false)
}
fn draw(&self, g: &mut GfxCtx, _: &App) {
self.top_center.draw(g);
}
}
// TODO Revive
#[allow(unused)]
fn faster_trips_panel(mode: TripMode, app: &App) -> Text {
let time = app.primary.sim.time();
let now = app
.primary
.sim
.get_analytics()
.trip_times(time)
.2
.remove(&mode)
.unwrap();
let baseline = app.prebaked().trip_times(time).2.remove(&mode).unwrap();
// Enable to debug why sim results don't match prebaked.
if false && !now.seems_eq(&baseline) {
abstutil::write_json(
"../current_sim.json".to_string(),
&app.primary.sim.get_analytics().finished_trips,
);
let filtered = app
.prebaked()
.finished_trips
.iter()
.filter(|(t, _, _, _)| *t <= time)
.cloned()
.collect::<Vec<_>>();
abstutil::write_json("../prebaked.json".to_string(), &filtered);
panic!("At {} ({:?}), finished_trips doesn't match", time, time);
}
let mut txt = Text::new();
txt.add_appended(vec![
Line(format!(
"{} trips {} (",
prettyprint_usize(now.count()),
mode.ongoing_verb()
)),
cmp_count_more(now.count(), baseline.count()),
Line(")"),
]);
if now.count() == 0 || baseline.count() == 0 {
return txt;
}
for stat in Statistic::all() {
txt.add(Line(format!("{}: {} (", stat, now.select(stat))));
txt.append_all(cmp_duration_shorter(
now.select(stat),
baseline.select(stat),
));
txt.append(Line(")"));
}
txt
}

View File

@ -1,5 +1,5 @@
mod commute;
mod create_gridlock;
mod faster_trips;
mod fix_traffic_signals;
mod freeform;
mod optimize_bus;
@ -26,7 +26,7 @@ use ezgui::{
use geom::{Duration, Polygon};
use map_model::{EditCmd, EditIntersection, Map, MapEdits};
use rand_xorshift::XorShiftRng;
use sim::{Analytics, Scenario, ScenarioGenerator, TripMode};
use sim::{Analytics, PersonID, Scenario, ScenarioGenerator};
#[derive(PartialEq, Clone)]
pub enum GameplayMode {
@ -39,12 +39,10 @@ pub enum GameplayMode {
OptimizeBus(String, String),
// Map path
CreateGridlock(String),
// TODO Be able to filter population by more factors
// Map path
FasterTrips(String, TripMode),
FixTrafficSignals,
// TODO Kinda gross. What stage in the tutorial?
FixTrafficSignalsTutorial(usize),
OptimizeCommute(PersonID),
// current
Tutorial(TutorialPointer),
@ -94,11 +92,11 @@ impl GameplayMode {
GameplayMode::PlayScenario(ref path, _) => path.to_string(),
GameplayMode::OptimizeBus(ref path, _) => path.to_string(),
GameplayMode::CreateGridlock(ref path) => path.to_string(),
GameplayMode::FasterTrips(ref path, _) => path.to_string(),
GameplayMode::FixTrafficSignals => abstutil::path_map("montlake"),
GameplayMode::FixTrafficSignalsTutorial(_) => {
abstutil::path_synthetic_map("signal_single")
}
GameplayMode::OptimizeCommute(_) => abstutil::path_map("montlake"),
GameplayMode::Tutorial(_) => abstutil::path_map("montlake"),
}
}
@ -257,12 +255,10 @@ impl GameplayMode {
GameplayMode::CreateGridlock(_) => {
create_gridlock::CreateGridlock::new(ctx, app, self.clone())
}
GameplayMode::FasterTrips(_, trip_mode) => {
faster_trips::FasterTrips::new(ctx, app, *trip_mode, self.clone())
}
GameplayMode::FixTrafficSignals | GameplayMode::FixTrafficSignalsTutorial(_) => {
fix_traffic_signals::FixTrafficSignals::new(ctx, app, self.clone())
}
GameplayMode::OptimizeCommute(p) => commute::OptimizeCommute::new(ctx, app, *p),
GameplayMode::Tutorial(current) => Tutorial::new(ctx, app, *current),
}
}