]> git.tdb.fi Git - r2c2.git/blobdiff - source/libr2c2/trainrouteplanner.cpp
Fix critical block logic
[r2c2.git] / source / libr2c2 / trainrouteplanner.cpp
index 0d0103cb3f4ef274cd1ea4544d2557f87a9fa8c5..9f19ffcdfb06ae470447ebeb5f01154845ae49ea 100644 (file)
@@ -22,14 +22,18 @@ TrainRoutePlanner::TrainRoutePlanner(Layout &layout):
        for(map<unsigned, Train *>::const_iterator i=trains.begin(); i!=trains.end(); ++i)
        {
                TrainRoutingInfo info(*i->second);
-               if(info.destination)
+               if(!info.waypoints.empty())
                        routed_trains.push_back(info);
        }
 }
 
 TrainRoutePlanner::~TrainRoutePlanner()
 {
-       delete thread;
+       if(thread)
+       {
+               thread->join();
+               delete thread;
+       }
 }
 
 TrainRoutePlanner::Result TrainRoutePlanner::plan()
@@ -55,9 +59,13 @@ TrainRoutePlanner::Result TrainRoutePlanner::check()
 {
        if(result==PENDING && goal)
        {
+               if(thread)
+               {
+                       thread->join();
+                       delete thread;
+                       thread = 0;
+               }
                finalize_plan();
-               delete thread;
-               thread = 0;
        }
 
        return result;
@@ -206,25 +214,20 @@ void TrainRoutePlanner::finalize_plan()
 TrainRoutePlanner::TrainRoutingInfo::TrainRoutingInfo(Train &t):
        train(&t),
        speed(train->get_maximum_speed()),
+       first_noncritical(train->get_last_critical_block().next().block()),
        router(train->get_ai_of_type<TrainRouter>()),
-       destination(0),
+       waypoints(router ? router->get_n_waypoints() : 0),
        has_duration(false)
 {
-       if(router)
+       if(!waypoints.empty())
        {
-               destination = router->get_destination();
-               if(destination)
+               metrics.resize(waypoints.size());
+               for(unsigned i=0; i<waypoints.size(); ++i)
                {
-                       waypoints.resize(router->get_n_waypoints());
-                       metrics.resize(waypoints.size()+1);
-                       metrics[0] = &router->get_metric(-1);
-                       for(unsigned i=0; i<waypoints.size(); ++i)
-                       {
-                               waypoints[i] = &router->get_waypoint(i);
-                               metrics[i+1] = &router->get_metric(i);
-                       }
-                       has_duration = router->get_trip_duration();
+                       waypoints[i] = &router->get_waypoint(i);
+                       metrics[i] = &router->get_metric(i);
                }
+               has_duration = router->get_trip_duration();
        }
 
        // If no maximum speed is specified, use a sensible default
@@ -264,11 +267,12 @@ TrainRoutePlanner::OccupiedTrack::~OccupiedTrack()
 
 TrainRoutePlanner::TrainRoutingState::TrainRoutingState(TrainRoutingInfo &inf):
        info(&inf),
+       critical(true),
        occupied_tracks(0),
        state(MOVING),
        delay(info->router->get_departure_delay()),
        duration(info->router->get_trip_duration()),
-       waypoint(info->waypoints.empty() ? -1 : 0),
+       waypoint(0),
        blocked_by(-1)
 {
        const Vehicle *veh = &info->train->get_vehicle(0);
@@ -299,6 +303,7 @@ TrainRoutePlanner::TrainRoutingState::TrainRoutingState(const TrainRoutingState
        info(other.info),
        track(other.track),
        path(other.path),
+       critical(other.critical),
        occupied_tracks(other.occupied_tracks),
        offset(other.offset),
        back_offset(other.back_offset),
@@ -341,18 +346,21 @@ bool TrainRoutePlanner::TrainRoutingState::check_arrival()
 {
        TrackIter next_track = track.next(path);
 
-       if(waypoint<0 && info->destination->has_track(*track) && !info->destination->has_track(*next_track))
-       {
-               state = ARRIVED;
-               return true;
-       }
-       else if(waypoint>=0 && info->waypoints[waypoint]->has_track(*track) && !info->waypoints[waypoint]->has_track(*next_track))
+       const TrackChain *wp_chain = info->waypoints[waypoint];
+       if(wp_chain->has_track(*track) && !wp_chain->has_track(*next_track))
        {
-               ++waypoint;
-               if(waypoint>=static_cast<int>(info->waypoints.size()))
-                       waypoint = -1;
+               if(waypoint+1<info->waypoints.size())
+                       ++waypoint;
+               else
+               {
+                       state = ARRIVED;
+                       return true;
+               }
        }
 
+       if(info->first_noncritical->has_track(*track))
+               critical = false;
+
        return false;
 }
 
@@ -361,20 +369,37 @@ void TrainRoutePlanner::TrainRoutingState::advance(float distance)
        offset += distance;
        back_offset += distance;
 
-       OccupiedTrack *last_occ = occupied_tracks;
-       for(unsigned n=occupied_tracks->n_tracks; n>1; --n)
-               last_occ = last_occ->next;
+       unsigned count_to_free = 0;
+       unsigned last_sensor_addr = 0;
+       float distance_after_sensor = 0;
+       OccupiedTrack *occ = occupied_tracks;
+       for(unsigned n=occupied_tracks->n_tracks; n>0; --n)
+       {
+               if(unsigned saddr = occ->track->get_sensor_address())
+               {
+                       if(saddr!=last_sensor_addr)
+                       {
+                               count_to_free = 0;
+                               distance_after_sensor = 0;
+                       }
+                       last_sensor_addr = saddr;
+               }
+
+               ++count_to_free;
+               distance_after_sensor += occ->path_length;
 
-       // XXX What if there's multiple tracks to remove?
-       if(back_offset>last_occ->path_length)
+               occ = occ->next;
+       }
+
+       if(count_to_free && back_offset>distance_after_sensor)
        {
-               back_offset -= last_occ->path_length;
+               back_offset -= distance_after_sensor;
                if(occupied_tracks->refcount>1)
                {
                        --occupied_tracks->refcount;
                        occupied_tracks = new OccupiedTrack(*occupied_tracks);
                }
-               --occupied_tracks->n_tracks;
+               occupied_tracks->n_tracks -= count_to_free;
        }
 
        distance_traveled += distance;
@@ -418,11 +443,20 @@ void TrainRoutePlanner::TrainRoutingState::advance_track(unsigned next_path)
 void TrainRoutePlanner::TrainRoutingState::update_estimate()
 {
        TrackIter iter = track.reverse(path);
-       float distance = info->metrics[waypoint+1]->get_distance_from(*iter.track(), iter.entry());
+       float distance = info->metrics[waypoint]->get_distance_from(*iter.track(), iter.entry());
        distance += track->get_type().get_path_length(path)-offset;
        remaining_estimate = distance;
 }
 
+bool TrainRoutePlanner::TrainRoutingState::is_viable() const
+{
+       if(remaining_estimate<0)
+               return false;
+       if(critical && state==BLOCKED)
+               return false;
+       return true;
+}
+
 
 TrainRoutePlanner::RoutingStep::RoutingStep():
        prev(0)
@@ -463,19 +497,29 @@ void TrainRoutePlanner::RoutingStep::create_successors(list<RoutingStep> &new_st
                return;
        }
 
-       TrackIter next_track = train.track.next(train.path);
        train.advance_track(0);
 
-       const TrackType::Endpoint &next_entry_ep = next_track.endpoint();
-       for(unsigned i=0; next_entry_ep.paths>>i; ++i)
-               if(next_entry_ep.has_path(i))
-               {
-                       train.path = i;
-                       train.update_estimate();
-                       next.update_estimate();
-                       if(next.is_viable())
-                               new_steps.push_back(next);
-               }
+       const TrackType::Endpoint &entry_ep = train.track.endpoint();
+       if(train.critical)
+       {
+               train.path = train.track->get_type().coerce_path(train.track.entry(), train.track->get_active_path());
+               train.update_estimate();
+               next.update_estimate();
+               if(next.is_viable())
+                       new_steps.push_back(next);
+       }
+       else
+       {
+               for(unsigned i=0; entry_ep.paths>>i; ++i)
+                       if(entry_ep.has_path(i))
+                       {
+                               train.path = i;
+                               train.update_estimate();
+                               next.update_estimate();
+                               if(next.is_viable())
+                                       new_steps.push_back(next);
+                       }
+       }
 
        new_steps.sort();
        for(list<RoutingStep>::iterator i=new_steps.begin(); ++i!=new_steps.end(); )
@@ -484,7 +528,7 @@ void TrainRoutePlanner::RoutingStep::create_successors(list<RoutingStep> &new_st
                i->update_estimate();
        }
 
-       if(next_entry_ep.paths!=next_track->get_type().get_paths())
+       if(entry_ep.paths!=train.track->get_type().get_paths() && !train.critical)
        {
                RoutingStep wait(this);
                wait.advance(dt);
@@ -511,7 +555,11 @@ bool TrainRoutePlanner::RoutingStep::update_states()
                {
                        i->blocked_by = get_occupant(*next_track);
                        if(i->blocked_by>=0)
+                       {
+                               if(i->info->first_noncritical->has_track(*next_track))
+                                       i->critical = false;
                                i->state = BLOCKED;
+                       }
                        else if(i->state==BLOCKED)
                                i->state = MOVING;
                }
@@ -595,7 +643,7 @@ void TrainRoutePlanner::RoutingStep::update_estimate()
 bool TrainRoutePlanner::RoutingStep::is_viable() const
 {
        for(vector<TrainRoutingState>::const_iterator i=trains.begin(); i!=trains.end(); ++i)
-               if(i->remaining_estimate<0)
+               if(!i->is_viable())
                        return false;
 
        for(vector<TrainRoutingState>::const_iterator i=trains.begin(); i!=trains.end(); ++i)