State safety_actual;
typedef struct TrackLocation TrackLocation;
-struct TrackLocation {
+struct TrackLocation { /* transparent, and manipulable by trackloc_... fns */
SegmentNum segn; /* current segment */
long into; /* distance from start of segment */
unsigned backwards:1; /* if 1, into is positive and measured from end */
};
-void trackloc_further(TrackLocation *tloc, long *remain_io);
+const SegmentLinkInfo *trackloc_segmentlink_near(const TrackLocation *tloc) {
+ SegmentState *seg = s->seg[tloc->segn];
+ const SegmentInfo *segi= &safety_segis[tloc->segn];
+
+ return (tloc->backwards ? &segi->forwards :
+ seg->pt_sideways ? &segi->sideways :
+ &segi->backwards);
+}
+
+const SegmentLinkInfo *trackloc_segmentlink_far(const TrackLocation *tloc) {
+ SegmentState *seg = s->seg[tloc->segn];
+ const SegmentInfo *segi= &safety_segis[tloc->segn];
+
+ return (tloc->backwards ? &segi->backwards :
+ seg->pt_sideways ? &segi->sideways :
+ &segi->forwards);
+}
+
+long trackloc_remaininseg(const TrackLocation *tloc) {
+ /* Returns dist that tloc can advance before it goes into next segment. */
+ State *s = &safety_state;
+ SegmentState *seg = s->seg[tloc->segn];
+ const SegmentInfo *segi= &safety_segis[tloc->segn];
+ const SegmentLinkInfo *lnki_near, *lnki_far;
+ long segment_len;
+
+ lnki_near= trackloc_segmentlink_near(tloc);
+ lnki_far= trackloc_segmentlink_far(tloc);
+ segment_len= linki_near->dist + link_far->dist;
+ assert(tloc->into <= segment_len);
+ return segment_len - tloc->info;
+}
+
+void trackloc_further(TrackLocation *tloc, long *remain_io) {
/* Advances tloc, decrementing *remain_io, until either
* *remain_io becomes zero, or tloc->segn changes. */
-
-long trackloc_remaininseg(const TrackLocation *tloc);
- /* Amount that tloc can advance before it goes into next segment. */
+ State *s = &safety_state;
+ SegmentState *seg = s->seg[tloc->segn];
+ const SegmentInfo *segi= &safety_segis[tloc->segn];
+ const SegmentLinkInfo *lnki_far;
+
+ segment_remain= trackloc_remaininseg(tloc);
+
+ if (*remain_io <= segment_remain) {
+ tloc->into += *remain_io;
+ *remain_io= 0;
+ } else {
+ lnki_far= trackloc_segmentlink_far(tloc);
+ *remain_io -= segment_remain;
+ tloc->segn= lnki_far->next;
+ tloc->into= 0;
+ tloc->backwards ^= lnki_far->next_backwards;
+ }
+}
static voi seg_clear_stale(SegmentState *seg) {
if (!seg->tr_updated) {
}
}
+void lay_train_checkclash(ErrorCode *ec, SegmentLinkInfo *lnki
+ TrainNum tran,) {
+ SegmentNum clash_segn;
+ SegmentState *clash_seg;
+ TrainNum clash_tran;
+ TrainState *clash_tra;
+
+ clash_segn= lnki->clashing;
+ if (clash_segn == NOTA(Segment)) return;
+
+ clash_seg= &s->segs[lnki->clashing];
+ if (!clash_seg->owned) return;
+
+ clash_tran= clash->owner;
+ clash_tra= &s->tras[clash_tran];
+
+ if (clash_tra->justarrived) {
+ TrackLocation clash_loc;
+ clash_loc.segn= clash_tra->foredetect;
+ clash_loc.
+
+
+= &s->segs[lnki->clashing];
+ if (clash->
+
+ lay_train_checkclash2(
+
static void lay_train(ErrorCode *ec, TrainNum tran,
TrackLocation tloc, long advance,
- unsigned detect, unsigned clash_if_updated) {
+ unsigned pass) {
+ /* pass 0: update actual train location, check for train clashing
+ * with itself (ie, fail if we find segment with same train and
+ * tr_updated set.
+ * pass 1: update detection only. Clashingness checking is
+ * done where it is convenient not to avoid it, but is not
+ * necessary. */
SegmentState *seg;
+ const SegmentInfo *segi;
long overall, remain;
if (*ec) return;
remain= overall= advance + tra->speed * SPEED_CLEAR_MULT;
for (;;) {
- seg= s->segs[tloc.segn];
- if (clash_if_updated && seg->tr_updated) {
- *ec= safety_problem(tloc.segn, tran, tran, "collision with itself");
- return;
- }
- if (seg->owned) {
- if (seg->owner != tran) {
- *ec= safety_problem(tloc.segn, tran, seg->owner, "collision");
+ seg= &s->segs[tloc.segn];
+ segi= &info_segment[tloc.segn];
+
+ if (pass==0) {
+ if (seg->tr_updated) {
+ *ec= safety_problem(tloc.segn, tran, tran, "collision with itself");
return;
}
- seg_clear_stale(seg);
+ if (seg->owned) {
+ if (seg->owner != tran) {
+ *ec= safety_problem(tloc.segn, tran, seg->owner, "collision");
+ return;
+ }
+ seg_clear_stale(seg);
+ }
}
+
seg->owned= 1;
seg->owner_backwards= tloc.backwards;
seg->tr_updated= 1;
seg->tran= tran;
+ seg->tr_justarrived= pass==0 && remain && tra->justarrived;
+
+ lay_train_checkclash(ec, trackloc_segmentlink_near());
+ if (!remain && tra->justarrived) {
+
+
+ if (tloc.into <= JUSTARRIVED_INTOMAX) {
+ seg->tr_justarrived= 1;
+ } else {
+ lay_train_checkclash(&ec, trackloc_segmentlink_far());
+ }
+
+
dist_until= (overall - remain) - advance;
time_until= (SPEED_FACTOR * dist_until) / tra->speed;
- *(detect ? &seg->until_detect : &seg->until_here)= time_until;
+ *(pass==0 ? &seg->until_here : &seg->until_detect)= time_until;
if (!remain) break;
trackloc_further(&tloc, &remain);
if (ec) return ec;
-
-
-
- segi= &safety_segis[segn];
- lnki1= (seg->reverse ? &segi->forwards :
- seg->sideways ? &segi->sideways :
- &segi->backwards);
- lnki2= (seg->reverse ? &segi->backwards :
- seg->sideways ? &segi->sideways :
- &segi->forwares);
-
tloc.segn= segn;
tloc.into=