+ while(begin!=end)
+ {
+ Block *block = begin->block;
+ blocks.erase(begin++);
+ block->reserve(0);
+ }
+}
+
+void Train::reverse_blocks(list<BlockRef> &blocks) const
+{
+ blocks.reverse();
+ for(list<BlockRef>::iterator i=blocks.begin(); i!=blocks.end(); ++i)
+ i->entry = i->block->traverse(i->entry);
+}
+
+bool Train::advance_route(list<RouteRef>::iterator &iter, Track &track)
+{
+ while(iter!=routes.end() && !iter->route->has_track(track))
+ ++iter;
+ if(iter==routes.end())
+ return false;
+
+ list<RouteRef>::iterator next = iter;
+ ++next;
+ if(next!=routes.end() && next->diversion && next->route->has_track(track))
+ iter = next;
+
+ return true;
+}
+
+Route *Train::create_lead_route(Route *lead, const Route *target)
+{
+ if(!lead)
+ {
+ lead = new Route(layout);
+ lead->set_name("Lead");
+ lead->set_temporary(true);
+ }
+
+ set<Track *> tracks;
+ for(list<BlockRef>::iterator i=cur_blocks.begin(); i!=rsv_blocks.end(); )
+ {
+ const set<Track *> &btracks = i->block->get_tracks();
+ for(set<Track *>::const_iterator j=btracks.begin(); j!=btracks.end(); ++j)
+ if(!target || !target->has_track(**j))
+ tracks.insert(*j);
+
+ if(++i==cur_blocks.end())
+ i = rsv_blocks.begin();
+ }
+
+ lead->add_tracks(tracks);
+
+ return lead;
+}
+
+bool Train::is_valid_diversion(const Route &diversion, Track &from, unsigned from_ep)
+{
+ float diversion_len = 0;
+ Track *track = &from;
+ unsigned ep = from_ep;
+ while(diversion.has_track(*track))
+ {
+ unsigned path = 0;
+ if(track->get_turnout_id())
+ path = diversion.get_turnout(track->get_turnout_id());
+ diversion_len += track->get_type().get_path_length(path);
+
+ Track *next = track->get_link(track->traverse(ep, path));
+ ep = next->get_endpoint_by_link(*track);
+ track = next;
+
+ if(track==&from)
+ return false;
+ }
+
+ list<RouteRef>::iterator route = routes.begin();
+ if(!advance_route(route, from))
+ return false;
+
+ set<Track *> visited;
+ float route_len = 0;
+ track = &from;
+ ep = from_ep;
+ while(1)
+ {
+ unsigned path = 0;
+ if(track->get_turnout_id())
+ path = route->route->get_turnout(track->get_turnout_id());
+ route_len += track->get_type().get_path_length(path);
+
+ if(track!=&from && diversion.has_track(*track))
+ break;
+
+ if(visited.count(track))
+ return false;
+ visited.insert(track);
+
+ Track *next = track->get_link(track->traverse(ep, path));
+ ep = next->get_endpoint_by_link(*track);
+ track = next;
+
+ if(!advance_route(route, *track))
+ return false;
+ }
+
+ return diversion_len<route_len*1.2;
+}
+
+
+Train::BlockRef::BlockRef(Block *b, unsigned e):
+ block(b),
+ entry(e)
+{ }
+
+Train::BlockRef Train::BlockRef::next() const
+{
+ Block *blk = block->get_endpoints()[block->traverse(entry)].link;
+ if(!blk)
+ throw InvalidState("At end of line");
+
+ int ep = blk->get_endpoint_by_link(*block);
+ if(ep<0)
+ throw LogicError("Block links are inconsistent");
+
+ return BlockRef(blk, ep);
+}
+
+
+Train::RouteRef::RouteRef(const Route *r, unsigned d):
+ route(r),
+ diversion(d)
+{ }
+
+
+Train::RealSpeed::RealSpeed():
+ speed(0),
+ weight(0)
+{ }
+
+void Train::RealSpeed::add(float s, float w)
+{
+ speed = (speed*weight+s*w)/(weight+w);
+ weight = min(weight+w, 300.0f);