From 738f50f5b8c53c38a5ab89166eb67ee3f99b4a44 Mon Sep 17 00:00:00 2001 From: Dustin Carlino Date: Sun, 1 May 2022 17:01:18 +0100 Subject: [PATCH] Prevent pedestrians from endlessly cutting off cars at a stop sign by limiting how long a crowd can enter a crosswalk. #517 Removing Tehran from prebaking; it starts gridlocking. I didn't investigate why; making SMP realistic unfortunately takes priority right now. --- apps/game/src/challenges/prebake.rs | 3 ++- sim/src/lib.rs | 4 +++ sim/src/mechanics/intersection.rs | 33 ++++++++++++++++++++++- tests/goldenfiles/prebaked_summaries.json | 13 +++------ 4 files changed, 41 insertions(+), 12 deletions(-) diff --git a/apps/game/src/challenges/prebake.rs b/apps/game/src/challenges/prebake.rs index 808decb2a4..0feb4218ab 100644 --- a/apps/game/src/challenges/prebake.rs +++ b/apps/game/src/challenges/prebake.rs @@ -53,7 +53,8 @@ pub fn prebake_all() { } } - { + // Started gridlocking with more realistic pedestrian crossing behavior + if false { let tehran_map = map_model::Map::load_synchronously( MapName::new("ir", "tehran", "parliament").path(), &mut timer, diff --git a/sim/src/lib.rs b/sim/src/lib.rs index 21ef80af80..9698ed7d75 100644 --- a/sim/src/lib.rs +++ b/sim/src/lib.rs @@ -169,6 +169,10 @@ impl AgentID { _ => false, } } + + pub(crate) fn is_pedestrian(&self) -> bool { + matches!(self, AgentID::Pedestrian(_)) + } } impl fmt::Display for AgentID { diff --git a/sim/src/mechanics/intersection.rs b/sim/src/mechanics/intersection.rs index 2692dd9f88..ef449b6378 100644 --- a/sim/src/mechanics/intersection.rs +++ b/sim/src/mechanics/intersection.rs @@ -847,7 +847,7 @@ impl IntersectionSimState { req: &Request, map: &Map, sign: &ControlStopSign, - _speed: Speed, + speed: Speed, now: Time, scheduler: &mut Scheduler, ) -> bool { @@ -881,6 +881,37 @@ impl IntersectionSimState { // TODO Make sure we can optimistically finish this turn before an approaching // higher-priority vehicle wants to begin. + // If a pedestrian is going to cut off a car, check how long the car has been waiting and + // maybe yield (regardless of stop sign priority). This is a very rough start to more + // realistic "batching" of pedestrians to cross a street. Without this, if there's one + // pedestrian almost clear of a crosswalk, cars are totally stopped for them, and so a new + // pedestrian arriving will win. + if req.agent.is_pedestrian() { + let our_turn = map.get_t(req.turn); + let time_to_cross = our_turn.geom.length() / speed; + for (other_req, (other_time, _)) in &self.state[&req.turn.parent].waiting { + if matches!(other_req.agent, AgentID::Car(_)) { + if our_turn.conflicts_with(map.get_t(other_req.turn)) { + let our_waiting = now - our_time; + let other_waiting = now - *other_time; + // We can't tell if a car has been waiting for a while due to pedestrians + // crossing, or due to a blockage in their destination queue. Always let + // pedestrians muscle their way in eventually. + if our_waiting > other_waiting { + continue; + } + // Intuition: another pedestrian trying to enter a crosswalk has a 3s + // buffer to "join" the first pedestrian who started crossing and caused + // cars to stop. We're using the time for _this_ pedestrian to cross _this_ + // turn, so it's a very rough definition. + if other_waiting > time_to_cross + Duration::seconds(3.0) { + return false; + } + } + } + } + } + true } diff --git a/tests/goldenfiles/prebaked_summaries.json b/tests/goldenfiles/prebaked_summaries.json index 3c468f57a5..81faf024df 100644 --- a/tests/goldenfiles/prebaked_summaries.json +++ b/tests/goldenfiles/prebaked_summaries.json @@ -4,27 +4,20 @@ "scenario": "weekday", "finished_trips": 76640, "cancelled_trips": 0, - "total_trip_duration_seconds": 43681790.01100022 + "total_trip_duration_seconds": 43931256.87820016 }, { "map": "montlake (in seattle (us))", "scenario": "weekday", "finished_trips": 36710, "cancelled_trips": 86, - "total_trip_duration_seconds": 18533522.79990011 - }, - { - "map": "parliament (in tehran (ir))", - "scenario": "random people going to and from work", - "finished_trips": 29350, - "cancelled_trips": 16734, - "total_trip_duration_seconds": 40298148.80850012 + "total_trip_duration_seconds": 18533435.094100088 }, { "map": "sao_miguel_paulista (in sao_paulo (br))", "scenario": "Full", "finished_trips": 122948, "cancelled_trips": 33043, - "total_trip_duration_seconds": 102103184.10710092 + "total_trip_duration_seconds": 86387963.54580107 } ] \ No newline at end of file