lots of the logic to start a parked car

This commit is contained in:
Dustin Carlino 2018-07-09 11:34:06 -07:00
parent dbc6cd1e67
commit d3bcbe1da2
6 changed files with 140 additions and 63 deletions

View File

@ -3,8 +3,10 @@
## cars ## cars
- model cars parking - model cars parking
- populate a bunch of parked cars initially - need to update the tests to seed, then start
- maybe render numbers on the cars to distinguish them - render parked cars (different color)
- make vanished cars just park again
- how to handle when parking is full or no parking at goal road?
- code cleanup - code cleanup
- try to simplify straw_model step (less phases?) - try to simplify straw_model step (less phases?)
@ -18,6 +20,7 @@
- draw cars in slightly different colors, to distinguish them better - draw cars in slightly different colors, to distinguish them better
- start implementing a second AORTAish driving model - start implementing a second AORTAish driving model
- then make cars park/unpark at the correct position
- reversible sim - reversible sim

View File

@ -414,9 +414,16 @@ impl gui::GUI for UI {
self.geom_validator = Validator::start(&self.draw_map); self.geom_validator = Validator::start(&self.draw_map);
return gui::EventLoopMode::InputOnly; return gui::EventLoopMode::InputOnly;
} }
if input.unimportant_key_pressed(Key::S, "Spawn 1000 cars in random places") { if self.sim_ctrl.sim.total_cars() == 0 {
self.sim_ctrl.sim.spawn_many_on_empty_roads(&self.map, 1000); if input.unimportant_key_pressed(Key::S, "Seed the map with 50% parked cars") {
return gui::EventLoopMode::InputOnly; self.sim_ctrl.sim.seed_parked_cars(0.5);
return gui::EventLoopMode::InputOnly;
}
} else {
if input.unimportant_key_pressed(Key::S, "Make 1000 parked cars start driving") {
self.sim_ctrl.sim.start_many_parked_cars(&self.map, 1000);
return gui::EventLoopMode::InputOnly;
}
} }
match self.current_selection_state { match self.current_selection_state {
@ -435,10 +442,8 @@ impl gui::GUI for UI {
} }
if self.map.get_r(id).lane_type == map_model::LaneType::Driving { if self.map.get_r(id).lane_type == map_model::LaneType::Driving {
if input.key_pressed(Key::A, "Press A to add a car starting from this road") { if input.key_pressed(Key::A, "Press A to start a parked car on this road") {
if !self.sim_ctrl.sim.spawn_one_on_road(&self.map, id) { self.sim_ctrl.sim.start_parked_car(&self.map, id);
println!("No room, sorry");
}
return gui::EventLoopMode::InputOnly; return gui::EventLoopMode::InputOnly;
} }
} }

View File

@ -5,7 +5,9 @@ use dimensioned::si;
use draw_car::DrawCar; use draw_car::DrawCar;
use geom::{Angle, Pt2D}; use geom::{Angle, Pt2D};
use intersections::{IntersectionPolicy, StopSign, TrafficSignal}; use intersections::{IntersectionPolicy, StopSign, TrafficSignal};
use map_model::{Map, RoadID, TurnID}; use map_model;
use rand::Rng;
use map_model::{Map, RoadID, TurnID, LaneType};
use multimap::MultiMap; use multimap::MultiMap;
use std; use std;
use std::collections::{BTreeMap, HashSet, VecDeque}; use std::collections::{BTreeMap, HashSet, VecDeque};
@ -393,4 +395,44 @@ impl DrivingSimState {
} }
} }
} }
// TODO cars basically start in the intersection, with their front bumper right at the
// beginning of the road. later, we want cars starting at arbitrary points in the middle of the
// road (from a building), so just ignore this problem for now.
// True if we spawned one
pub fn start_car_on_road<R: Rng + ?Sized>(&mut self, time: Tick, start: RoadID, car: CarID, map: &Map, rng: &mut R) -> bool {
if !self.roads[start.0].room_at_end(time, &self.cars) {
// TODO car should enter Unparking state and wait for room
println!("No room for {} to start driving on {}", car, start);
return false;
}
let goal = rng.choose(map.all_roads()).unwrap();
if goal.lane_type != LaneType::Driving || goal.id == start {
println!("Chose bad goal {}", goal.id);
return false;
}
let mut path = if let Some(steps) = map_model::pathfind(map, start, goal.id) {
VecDeque::from(steps)
} else {
println!("No path from {} to {}", start, goal.id);
return false;
};
// path includes the start, but that's not the invariant Car enforces
path.pop_front();
self.cars.insert(
car,
Car {
id: car,
path,
started_at: time,
on: On::Road(start),
waiting_for: None,
debug: false,
},
);
self.roads[start.0].cars_queue.push(car);
true
}
} }

View File

@ -22,10 +22,17 @@ mod sim;
use dimensioned::si; use dimensioned::si;
pub use sim::{Benchmark, Sim}; pub use sim::{Benchmark, Sim};
use std::fmt;
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct CarID(pub usize); pub struct CarID(pub usize);
impl fmt::Display for CarID {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "CarID({0})", self.0)
}
}
pub const TIMESTEP: si::Second<f64> = si::Second { pub const TIMESTEP: si::Second<f64> = si::Second {
value_unsafe: 0.1, value_unsafe: 0.1,
_marker: std::marker::PhantomData, _marker: std::marker::PhantomData,

View File

@ -20,7 +20,7 @@ impl ParkingSimState {
} }
// Kind of vague whether this should handle existing spots or not // Kind of vague whether this should handle existing spots or not
pub(crate) fn seed_random_cars<R: Rng + ?Sized>(&mut self, rng: &mut R, percent_capacity_to_fill: f64) { pub(crate) fn seed_random_cars<R: Rng + ?Sized>(&mut self, rng: &mut R, percent_capacity_to_fill: f64, id_counter: &mut usize) {
assert!(percent_capacity_to_fill >= 0.0 && percent_capacity_to_fill <= 1.0); assert!(percent_capacity_to_fill >= 0.0 && percent_capacity_to_fill <= 1.0);
let mut total_capacity = 0; let mut total_capacity = 0;
@ -33,7 +33,8 @@ impl ParkingSimState {
for spot in &mut r.spots { for spot in &mut r.spots {
if !spot.is_some() && rng.gen_bool(percent_capacity_to_fill) { if !spot.is_some() && rng.gen_bool(percent_capacity_to_fill) {
new_cars += 1; new_cars += 1;
*spot = Some(CarID(42)); // TODO create a new car, right? *spot = Some(CarID(*id_counter));
*id_counter += 1;
} }
} }
} }
@ -42,6 +43,14 @@ impl ParkingSimState {
new_cars, total_capacity new_cars, total_capacity
); );
} }
pub(crate) fn get_last_parked_car(&self, id: RoadID) -> Option<CarID> {
self.roads[id.0].get_last_parked_car()
}
pub(crate) fn remove_last_parked_car(&self, id: RoadID, car: CarID) {
self.roads[id.0].remove_last_parked_car(car)
}
} }
#[derive(Serialize, Deserialize, PartialEq, Eq)] #[derive(Serialize, Deserialize, PartialEq, Eq)]
@ -64,4 +73,14 @@ impl ParkingLane {
spots: iter::repeat(None).take(r.number_parking_spots()).collect(), spots: iter::repeat(None).take(r.number_parking_spots()).collect(),
} }
} }
fn get_last_parked_car(&self) -> Option<CarID> {
self.spots.iter().rfind(|&&x| x.is_some()).map(|r| r.unwrap())
}
fn remove_last_parked_car(&mut self, car: CarID) {
let idx = self.spots.iter().rposition(|&x| x.is_some()).expect("No parked cars at all now");
assert_eq!(self.spots[idx], Some(car));
self.spots[idx] = None;
}
} }

View File

@ -3,11 +3,9 @@
use control::ControlMap; use control::ControlMap;
use dimensioned::si; use dimensioned::si;
use draw_car::DrawCar; use draw_car::DrawCar;
use driving::{Car, DrivingSimState, On}; use driving::DrivingSimState;
use map_model;
use map_model::{LaneType, Map, RoadID, TurnID}; use map_model::{LaneType, Map, RoadID, TurnID};
use rand::{FromEntropy, Rng, SeedableRng, XorShiftRng}; use rand::{FromEntropy, Rng, SeedableRng, XorShiftRng};
use std::collections::VecDeque;
use parking::ParkingSimState; use parking::ParkingSimState;
use std::f64; use std::f64;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
@ -45,75 +43,78 @@ impl Sim {
} }
} }
// TODO cars basically start in the intersection, with their front bumper right at the pub fn total_cars(&self) -> usize {
// beginning of the road. later, we want cars starting at arbitrary points in the middle of the self.id_counter
// road (from a building), so just ignore this problem for now.
pub fn spawn_one_on_road(&mut self, map: &Map, start: RoadID) -> bool {
if !self.driving_state.roads[start.0].room_at_end(self.time, &self.driving_state.cars) {
return false;
}
let id = CarID(self.id_counter);
self.id_counter += 1;
let goal = self.rng.choose(map.all_roads()).unwrap();
if goal.lane_type != LaneType::Driving || goal.id == start {
println!("Chose bad goal {}", goal.id);
return false;
}
let mut path = if let Some(steps) = map_model::pathfind(map, start, goal.id) {
VecDeque::from(steps)
} else {
println!("No path from {} to {}", start, goal.id);
return false;
};
// path includes the start, but that's not the invariant Car enforces
path.pop_front();
self.driving_state.cars.insert(
id,
Car {
id,
path,
started_at: self.time,
on: On::Road(start),
waiting_for: None,
debug: false,
},
);
self.driving_state.roads[start.0].cars_queue.push(id);
true
} }
pub fn spawn_many_on_empty_roads(&mut self, map: &Map, num_cars: usize) { pub fn seed_parked_cars(&mut self, percent: f64) {
let mut roads: Vec<RoadID> = self.driving_state self.parking_state.seed_random_cars(&mut self.rng, percent, &mut self.id_counter)
.roads }
.iter()
pub fn start_many_parked_cars(&mut self, map: &Map, num_cars: usize) {
let mut driving_lanes: Vec<RoadID> = map.all_roads().iter()
.filter_map(|r| { .filter_map(|r| {
if map.get_r(r.id.as_road()).lane_type == LaneType::Driving && r.is_empty() { if r.lane_type == LaneType::Driving && self.driving_state.roads[r.id.0].is_empty() {
Some(r.id.as_road()) Some(r.id)
} else { } else {
None None
} }
}) })
.collect(); .collect();
// Don't ruin determinism for silly reasons. :) // Don't ruin determinism for silly reasons. :)
if !roads.is_empty() { if !driving_lanes.is_empty() {
self.rng.shuffle(&mut roads); self.rng.shuffle(&mut driving_lanes);
} }
let n = num_cars.min(roads.len()); let n = num_cars.min(driving_lanes.len());
let mut actual = 0; let mut actual = 0;
for i in 0..n { for i in 0..n {
if self.spawn_one_on_road(map, roads[i]) { if self.start_parked_car(map, driving_lanes[i]) {
actual += 1; actual += 1;
} }
} }
println!("Spawned {} of {}", actual, n); println!("Started {} parked cars of requested {}", actual, n);
}
pub fn start_parked_car(&mut self, map: &Map, id: RoadID) -> bool {
let (driving_lane, parking_lane) = match map.get_r(id).lane_type {
LaneType::Sidewalk => {
println!("{} is a sidewalk, can't start a parked car here", id);
return false;
}
LaneType::Driving => {
if let Some(parking) = map.find_parking_lane(id) {
(id, parking)
} else {
println!("{} has no parking lane", id);
return false;
}
}
LaneType::Parking => {
if let Some(driving) = map.find_driving_lane(id) {
(driving, id)
} else {
println!("{} has no driving lane", id);
return false;
}
}
};
if let Some(car) = self.parking_state.get_last_parked_car(parking_lane) {
if self.driving_state.start_car_on_road(self.time, driving_lane, car, map, &mut self.rng) {
self.parking_state.remove_last_parked_car(parking_lane, car);
}
true
} else {
println!("No parked cars on {}", parking_lane);
false
}
} }
pub fn step(&mut self, map: &Map, control_map: &ControlMap) { pub fn step(&mut self, map: &Map, control_map: &ControlMap) {
self.time.increment(); self.time.increment();
// TODO Vanish action should become Park
self.driving_state.step(self.time, map, control_map); self.driving_state.step(self.time, map, control_map);
} }