moving part of car behavior to an immutable reaction to a worldview

This commit is contained in:
Dustin Carlino 2018-07-30 15:10:45 -07:00
parent 6cc8489dfa
commit fe62537ee3

View File

@ -51,11 +51,12 @@ impl Car {
] ]
} }
fn step(&self, map: &Map, time: Tick) -> Action { // Note this doesn't change the car's state, and it observes a fixed view of the world!
fn react(&self, map: &Map, time: Tick, sim: &DrivingSimState) -> Action {
let desired_on: On = {
if let Some(on) = self.waiting_for { if let Some(on) = self.waiting_for {
return Action::Goto(on); on
} } else {
let dist = SPEED_LIMIT * (time - self.started_at).as_time(); let dist = SPEED_LIMIT * (time - self.started_at).as_time();
if dist < self.on.length(map) { if dist < self.on.length(map) {
return Action::Continue; return Action::Continue;
@ -67,12 +68,26 @@ impl Car {
} }
match self.on { match self.on {
// TODO cant try to go to next lane unless we're the front car On::Lane(id) => On::Turn(self.choose_turn(id, map)),
// if we dont do this here, we wont be able to see what turns people are waiting for On::Turn(id) => On::Lane(map.get_t(id).dst),
// even if we wait till we're the front car, we might unravel the line of queued cars }
// too quickly }
On::Lane(id) => Action::Goto(On::Turn(self.choose_turn(id, map))), };
On::Turn(id) => Action::Goto(On::Lane(map.get_t(id).dst)),
// Can we actually go there right now?
// In a more detailed driving model, this would do things like lookahead.
let has_room_now = match desired_on {
On::Lane(id) => sim.lanes[id.0].room_at_end(time, &sim.cars),
On::Turn(id) => sim.turns[&id].room_at_end(time, &sim.cars),
};
let is_lead_vehicle = match self.on {
On::Lane(id) => sim.lanes[id.0].cars_queue[0] == self.id,
On::Turn(id) => sim.turns[&id].cars_queue[0] == self.id,
};
if has_room_now && is_lead_vehicle {
Action::Goto(desired_on)
} else {
Action::WaitFor(desired_on)
} }
} }
@ -265,35 +280,10 @@ impl DrivingSimState {
control_map: &ControlMap, control_map: &ControlMap,
intersections: &mut IntersectionSimState, intersections: &mut IntersectionSimState,
) { ) {
// Could be concurrent, since this is deterministic. Note no RNG. Ask all cars for their // Could be concurrent, since this is deterministic.
// move, reinterpreting Goto to see if there's room now. It's important to query
// has_room_now here using the previous, fixed state of the world. If we did it in the next
// loop, then order of updates would matter for more than just conflict resolution.
let mut requested_moves: Vec<(CarID, Action)> = Vec::new(); let mut requested_moves: Vec<(CarID, Action)> = Vec::new();
for c in self.cars.values() { for c in self.cars.values() {
requested_moves.push(( requested_moves.push((c.id, c.react(map, time, &self)));
c.id,
match c.step(map, time) {
Action::Goto(on) => {
// This is a monotonic property in conjunction with
// new_car_entered_this_step. The last car won't go backwards.
let has_room_now = match on {
On::Lane(id) => self.lanes[id.0].room_at_end(time, &self.cars),
On::Turn(id) => self.turns[&id].room_at_end(time, &self.cars),
};
let is_lead_vehicle = match c.on {
On::Lane(id) => self.lanes[id.0].cars_queue[0] == c.id,
On::Turn(id) => self.turns[&id].cars_queue[0] == c.id,
};
if has_room_now && is_lead_vehicle {
Action::Goto(on)
} else {
Action::WaitFor(on)
}
}
x => x,
},
));
} }
// Apply moves, resolving conflicts. This has to happen serially. // Apply moves, resolving conflicts. This has to happen serially.