Skip to content

Commit

Permalink
handle random vehicles better
Browse files Browse the repository at this point in the history
  • Loading branch information
Uriopass committed Aug 13, 2023
1 parent 1364cfe commit b6bc4fb
Show file tree
Hide file tree
Showing 7 changed files with 267 additions and 64 deletions.
1 change: 1 addition & 0 deletions common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ pub mod history;
pub mod logger;
pub mod rand;
pub mod saveload;
pub mod scroll;
pub mod timestep;

pub use inline_tweak as tw;
Expand Down
196 changes: 196 additions & 0 deletions common/src/scroll.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
use serde::{Deserialize, Serialize};
use std::collections::{BTreeMap, BTreeSet};
use std::ops::Bound;

/// BTreeMapScroller helps traversing a btree in multiple steps without keeping a reference to the btree, using a pivot point each time
/// The idea is for example to do 0..10 then 10..20 then 20..30 etc
/// The BTree allows to do this efficiently
/// All keys won't necessarily be traversed if the tree changes between next() calls
#[derive(Default, Serialize, Deserialize)]
pub struct BTreeMapScroller<K: Ord + Clone> {
pub pivot: Option<K>,
}

/// BTreeSetScroller helps traversing a btree set in multiple steps without keeping a reference to the btree, using a pivot point each time
/// The idea is for example to do 0..10 then 10..20 then 20..30 etc
/// The BTree allows to do this efficiently
/// All keys won't necessarily be traversed if the tree changes between next() calls
#[derive(Default, Serialize, Deserialize)]
pub struct BTreeSetScroller<K: Ord + Clone> {
pub pivot: Option<K>,
}

impl<K: Ord + Clone> BTreeMapScroller<K> {
/// See [`BTreeMapScroller`](struct.BTreeMapScroller.html) for more details
pub fn new() -> Self {
Self { pivot: None }
}

pub fn reset(&mut self) {
self.pivot = None;
}

/// Checks if the iterator is exhausted, meaning that the next call to iter() will return an empty iterator
/// This is useful to know if we need to start to scroll again
pub fn exhausted<V>(&self, btree: &BTreeMap<K, V>) -> bool {
self.pivot.is_some()
&& btree
.range((
Bound::Excluded(self.pivot.as_ref().unwrap()),
Bound::Unbounded,
))
.next()
.is_none()
}

/// See [`BTreeMapScroller`](struct.BTreeMapScroller.html) for more details
pub fn iter<'a, V>(&'a mut self, btree: &'a BTreeMap<K, V>) -> impl Iterator<Item = (&K, &V)> {
let left_bound;
if let Some(x) = self.pivot.take() {
left_bound = Bound::Excluded(x);
} else {
left_bound = Bound::Unbounded;
};

btree.range((left_bound, Bound::Unbounded)).map(|x| {
self.pivot = Some(x.0.clone());
x
})
}

/// See [`BTreeMapScroller`](struct.BTreeMapScroller.html) for more details
pub fn iter_mut<'a, V>(
&'a mut self,
btree: &'a mut BTreeMap<K, V>,
) -> impl Iterator<Item = (&K, &mut V)> {
let left_bound;
if let Some(x) = self.pivot.take() {
left_bound = Bound::Excluded(x);
} else {
left_bound = Bound::Unbounded;
};
btree.range_mut((left_bound, Bound::Unbounded)).map(|x| {
self.pivot = Some(x.0.clone());
x
})
}
}

impl<K: Ord + Clone> BTreeSetScroller<K> {
/// See [`BTreeSetScroller`](struct.BTreeSetScroller.html) for more details
pub fn new() -> Self {
Self { pivot: None }
}

/// Checks if the iterator is exhausted, meaning that the next call to iter() will return an empty iterator
/// This is useful to know if we need to start to scroll again
pub fn exhausted(&self, btree: &BTreeSet<K>) -> bool {
self.pivot.is_some()
&& btree
.range((
Bound::Excluded(self.pivot.as_ref().unwrap()),
Bound::Unbounded,
))
.next()
.is_none()
}

pub fn reset(&mut self) {
self.pivot = None;
}

/// See [`BTreeSetScroller`](struct.BTreeSetScroller.html) for more details
/// Returns an iterator over the keys of the btree, but the iterator can stop without a ref to the btree and can start again
pub fn iter<'a>(&'a mut self, btree: &'a BTreeSet<K>) -> impl Iterator<Item = &K> {
let left_bound;
if let Some(x) = self.pivot.take() {
left_bound = Bound::Excluded(x);
} else {
left_bound = Bound::Unbounded;
};

btree.range((left_bound, Bound::Unbounded)).map(|x| {
self.pivot = Some(x.clone());
x
})
}

/// See [`BTreeSetScroller`](struct.BTreeSetScroller.html) for more details
/// Returns an iterator over the keys of the btree, but the iterator can stop without a ref to the btree and can start again
/// The iterator will start again from the beginning on the next iter_looped call when it reaches the end
/// This is not an infinite iterator, any key may not be processed twice in a single iter_looped call
pub fn iter_looped<'a>(&'a mut self, btree: &'a BTreeSet<K>) -> impl Iterator<Item = &K> {
if self.exhausted(btree) {
self.reset();
}
let left_bound;
if let Some(x) = self.pivot.take() {
left_bound = Bound::Excluded(x);
} else {
left_bound = Bound::Unbounded;
};

btree.range((left_bound, Bound::Unbounded)).map(|x| {
self.pivot = Some(x.clone());
x
})
}
}

#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_btree_map_iter() {
let mut scroller = BTreeMapScroller::new();

let mut btree = BTreeMap::new();
btree.insert(1, 1);
btree.insert(2, 2);
btree.insert(3, 3);

let mut iter = scroller.iter(&btree);
assert_eq!(iter.next(), Some((&1, &1)));
assert_eq!(iter.next(), Some((&2, &2)));
drop(iter);
let mut iter = scroller.iter(&btree);
assert_eq!(iter.next(), Some((&3, &3)));
assert_eq!(iter.next(), None);
}

#[test]
fn test_btree_map_iter_mut() {
let mut scroller = BTreeMapScroller::new();

let mut btree = BTreeMap::new();
btree.insert(1, 1);
btree.insert(2, 2);
btree.insert(3, 3);

let mut iter = scroller.iter_mut(&mut btree);
assert_eq!(iter.next(), Some((&1, &mut 1)));
assert_eq!(iter.next(), Some((&2, &mut 2)));
drop(iter);
let mut iter = scroller.iter_mut(&mut btree);
assert_eq!(iter.next(), Some((&3, &mut 3)));
assert_eq!(iter.next(), None);
}

#[test]
fn test_btree_set_iter() {
let mut scroller = BTreeSetScroller::new();

let mut btree = BTreeSet::new();
btree.insert(1);
btree.insert(2);
btree.insert(3);

let mut iter = scroller.iter(&btree);
assert_eq!(iter.next(), Some(&1));
assert_eq!(iter.next(), Some(&2));
drop(iter);
let mut iter = scroller.iter(&btree);
assert_eq!(iter.next(), Some(&3));
assert_eq!(iter.next(), None);
}
}
9 changes: 5 additions & 4 deletions egregoria/src/engine_interaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ use crate::economy::Government;
use crate::map::procgen::{load_parismap, load_testfield};
use crate::map::{
BuildingGen, BuildingID, BuildingKind, IntersectionID, LaneID, LanePattern, LanePatternBuilder,
LightPolicy, LotID, Map, MapProject, PathKind, ProjectKind, RoadID, Terrain, TurnPolicy, Zone,
LightPolicy, LotID, Map, MapProject, ProjectKind, RoadID, Terrain, TurnPolicy, Zone,
};
use crate::map_dynamic::{BuildingInfos, Itinerary, ParkingManagement};
use crate::map_dynamic::{BuildingInfos, ParkingManagement};
use crate::transportation::testing_vehicles::RandomVehicles;
use crate::transportation::train::{spawn_train, RailWagonKind};
use crate::transportation::{spawn_parked_vehicle_with_spot, unpark, VehicleKind};
use crate::utils::rand_provider::RandProvider;
Expand All @@ -14,6 +15,7 @@ use geom::{vec3, Vec2, OBB};
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::time::Instant;

use WorldCommand::*;

#[derive(Clone, Default)]
Expand Down Expand Up @@ -313,8 +315,7 @@ impl WorldCommand {
let Some(v_id) = spawn_parked_vehicle_with_spot(goria, VehicleKind::Car, spot) else { continue; };
unpark(goria, v_id);

goria.world.vehicles.get_mut(v_id).unwrap().it =
Itinerary::random(PathKind::Vehicle);
goria.write::<RandomVehicles>().vehicles.insert(v_id);
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions egregoria/src/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use crate::souls::goods_company::{company_system, GoodsCompanyRegistry};
use crate::souls::human::update_decision_system;
use crate::transportation::pedestrian_decision_system;
use crate::transportation::road::{vehicle_decision_system, vehicle_state_update_system};
use crate::transportation::testing_vehicles::{random_vehicles_update, RandomVehicles};
use crate::transportation::train::{
locomotive_system, train_reservations_update, TrainReservations,
};
Expand Down Expand Up @@ -41,6 +42,7 @@ pub fn init() {
register_system("market_update", market_update);
register_system("train_reservations_update", train_reservations_update);
register_system("freight_station", freight_station_system);
register_system("random_vehicles", random_vehicles_update);

register_system_goria("add_souls_to_empty_buildings", add_souls_to_empty_buildings);

Expand All @@ -58,6 +60,7 @@ pub fn init() {

register_init(init_market);

register_resource_default::<RandomVehicles, Bincode>("random_vehicles");
register_resource_default::<Tick, Bincode>("tick");
register_resource_default::<Map, Bincode>("map");
register_resource_default::<TrainReservations, Bincode>("train_reservations");
Expand Down
Loading

0 comments on commit b6bc4fb

Please sign in to comment.