mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-01 02:33:54 +03:00
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:
parent
eb1ea20a37
commit
ef2a237c5d
@ -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
|
||||
}
|
||||
|
108
game/src/sandbox/gameplay/commute.rs
Normal file
108
game/src/sandbox/gameplay/commute.rs
Normal 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)
|
||||
}
|
@ -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
|
||||
}
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user