]> git.tdb.fi Git - r2c2.git/blobdiff - source/libr2c2/trainrouteplanner.cpp
Avoid unnecessary wait time with shared destinations
[r2c2.git] / source / libr2c2 / trainrouteplanner.cpp
index b9bbfbcf1760c494d39c62464a1fdb4a5271333b..7aba4a68ed33e7ba0e3e434e655da77bd1dd02b9 100644 (file)
@@ -308,6 +308,7 @@ TrainRoutePlanner::TrainRoutingState::TrainRoutingState(TrainRoutingInfo &inf):
        delay(info->router->get_departure_delay()),
        duration(info->router->get_trip_duration()),
        waypoint(0),
+       distance_traveled(0),
        blocked_by(-1)
 {
        const Vehicle *veh = &info->train->get_vehicle(0);
@@ -366,13 +367,16 @@ TrainRoutePlanner::TrainRoutingState::~TrainRoutingState()
 
 Time::TimeDelta TrainRoutePlanner::TrainRoutingState::get_time_to_next_track() const
 {
-       return ((occupied_tracks->path_length-offset)/info->speed)*Time::sec+delay;
+       return ((occupied_tracks->path_length-offset)/info->speed)*Time::sec+delay+estimated_wait;
 }
 
 Time::TimeDelta TrainRoutePlanner::TrainRoutingState::get_time_to_pass(Track &trk) const
 {
        if(is_occupying(trk))
        {
+               if(state==ARRIVED && info->has_duration)
+                       return duration;
+
                float passed_length = 0;
                for(const OccupiedTrack *occ=occupied_tracks; (occ && occ->track!=&trk); occ=occ->next)
                        passed_length += occ->path_length;
@@ -479,7 +483,7 @@ void TrainRoutePlanner::TrainRoutingState::advance(const Time::TimeDelta &dt)
        }
 
        float secs = dt/Time::sec;
-       // There may be negative delay remaining after previous step.
+       // There may be some delay remaining.
        if(delay)
        {
                secs -= delay/Time::sec;
@@ -492,10 +496,20 @@ void TrainRoutePlanner::TrainRoutingState::advance(const Time::TimeDelta &dt)
        if(estimated_wait)
                estimated_wait = max(estimated_wait-secs*Time::sec, Time::zero);
 
-       if(state==MOVING)
+       float distance = info->speed*secs;
+       float remaining_on_track = occupied_tracks->path_length-offset;
+       if(state==MOVING || distance<remaining_on_track)
                advance(info->speed*secs);
        else if(state!=ARRIVED)
-               wait_time += secs*Time::sec;
+       {
+               if(remaining_on_track>0)
+               {
+                       advance(remaining_on_track);
+                       wait_time += (secs-remaining_on_track/info->speed)*Time::sec;
+               }
+               else
+                       wait_time += secs*Time::sec;
+       }
 }
 
 void TrainRoutePlanner::TrainRoutingState::advance_track(unsigned next_path)
@@ -560,7 +574,7 @@ void TrainRoutePlanner::RoutingStep::create_successors(list<RoutingStep> &new_st
        if(next.update_states() && next.check_deadlocks())
                return;
 
-       int train_index = find_next_train();
+       int train_index = next.find_next_train();
        if(train_index<0)
                return;
 
@@ -577,7 +591,13 @@ void TrainRoutePlanner::RoutingStep::create_successors(list<RoutingStep> &new_st
                return;
        }
 
-       train.advance_track(0);
+       if(train.state==MOVING)
+               train.advance_track(0);
+       else
+       {
+               new_steps.push_back(next);
+               return;
+       }
 
        const TrackType::Endpoint &entry_ep = train.track.endpoint();
        if(train.critical)
@@ -711,18 +731,27 @@ int TrainRoutePlanner::RoutingStep::get_occupant(Track &track) const
 
 int TrainRoutePlanner::RoutingStep::find_next_train() const
 {
+       /* Pick a moving train with the lowest time to next track.  A train that
+       just became blocked can still travel until the end of its current track,
+       so consider those too. */
        Time::TimeDelta min_dt;
        int next_train = -1;
        for(unsigned i=0; i<trains.size(); ++i)
-               if(trains[i].state==MOVING)
+       {
+               Time::TimeDelta dt;
+               if(trains[i].state==MOVING || (trains[i].state==BLOCKED && prev && prev->trains[i].state==MOVING))
+                       dt = trains[i].get_time_to_next_track();
+               else if(trains[i].state==BLOCKED && trains[trains[i].blocked_by].state==ARRIVED)
+                       dt = trains[i].estimated_wait;
+               else
+                       continue;
+
+               if(dt<min_dt || next_train<0)
                {
-                       Time::TimeDelta dt = trains[i].get_time_to_next_track();
-                       if(dt<min_dt || next_train<0)
-                       {
-                               min_dt = dt;
-                               next_train = i;
-                       }
+                       min_dt = dt;
+                       next_train = i;
                }
+       }
 
        return next_train;
 }