This document discusses several enhancements to the signalling systems in OpenTTD (currently at 0.5.0RC3), in order to achieve a flat 4-way junction allowing multiple-train use whenever possible. Path-Based Signalling (PBS) might already be able to achieve this, but isn't in the normal builds yet, and it depends on New (Global) Pathfinding (NPF) being enabled, which is processor-intensive (so I've read somewhere?; perhaps I'm overstating…).

The signalling enhancements comprise changes in determination of the state of plain signals and pre-signals by reducing the area of track that affects them, and the introduction of a new signal type (permanent red).

A track-signal notation with a plan view is also introduced, to help explain the new rules, and to depict the new signal type.

This document is intended:

The document was presented in the OpenTTD Suggestions forum on 2007-Jan-23.

Contents

  1. Goals
  2. Terminology
  3. Current rules for signalling
  4. A plan-view notation
  5. Signalling enhancements
    1. Problems with and corrections for obstruction inspection
    2. Problems with and corrections for no-exit inspection
    3. A flat, multitrain, 4-way junction
    4. Explicit permanent-red signals
  6. Specification of new inspection rules
    1. Inspection rules for the obstruction condition
    2. Inspection rules for the no-exit condition
    3. Observations of the new rules
  7. Verification of the new inspection rules against a junction
  8. Other uses
    1. Station sponge
    2. Dead-end depot
  9. Implementation
    1. Old rules
    2. New rules
  10. Summary
    1. Caveats

Goals

Fast, compact 4-way junctions are difficult to design. The simplest (most naïve) junctions are prone to deadlock, as they permit trains to enter a critical, exclusive section in use by perpendicular track without guaranteeing a way out. Even without deadlock, a junction might not be ‘multitasking’ — one train might have to wait while another uses the junction, even though they don't actually share any piece of track, which slows things down more than should be necessary.

More robust junctions involve tunnels or bridges, and therefore ramps, which slow trains down. Bridges and tunnels also cannot have signals, and bridges also have speed restrictions, so throughput is reduced. They also take up more space than the naïvely simple junctions.

Can we refine the rules for signals to improve the situation, and achieve a fast, multitasking, level, 4-way junction?

Terminology

prograde

A prograde signal is one whose face can be seen or observed, e.g. by a train driver, or by another signal whose state could depend on it.

retrograde

A retrograde signal faces the ‘wrong’ way. The observer only sees the back of it.

ingress
egress

To avoid confusion with established terms like pre-entry and pre-exit, we'll use the terms ingress and egress to identify the roles of signals that control entry to or exit from a piece of track, a depot, a station, etc.

Any signal can be prograde or retrograde depending on the observer, or ingress or egress depending on the entity in question.

Current rules for signalling

There are plain signals, pre-entry signals and pre-exit signals, plus a combination of the last two. This is a description of how they appear to work; the actual implementation is another matter.

Plain signals go red under one condition: obstruction. Imagine you are a train driver, approaching or waiting at a prograde signal (we'll call this the ingress signal of the track ahead). It is saying something about the track ahead, whether it is safe to proceed. To do this, you can imagine that it inspects the track ahead, i.e. it ‘looks’ along the track for other trains and signals (egress signals). If the track branches, or crosses another track, the signal must inspect both branches, or along the other track too. It can stop searching a branch when it encounters a train or a signal. If all branches lead to a signal, it reports green. If any lead to a train, it reports red. (The signal's range of inspection seems to flood along connected tracks, until stopped by trains or signals.)

It doesn't matter to the inspection if a branch leads to an apparently unidirectional egress signal. If the egress signal is facing you, and there is a train beyond it, it is safe to go at least as far as the signal. If the signal is facing away from you, then you can't possibly use it as a route; it is as if there is another signal which is facing you, but it is permanently red. Indeed, it may be helpful to think of every unidirectional signal as having an implicit permanent red facing in the opposite direction. Similarly, the end of a track has an implicit permanent red. In either case, if a train encounters one of these, it immediately turns back. (In contrast, if it encounters a red signal which could go to green, it will wait for some time before turning back.)

Pre-entry and pre-combo signals go red under two conditions: obstruction or ‘no-exit’. Obstruction is identical to that of plain signals.

To determine no-exit, the pre-entry/combo signal ‘looks ahead’ just as a plain signal would do, but it's only looking for pre-exit/combo signals. (If there were any trains, the obstruction condition would already be true, and there would be no need to check for no-exit — the signal would already be on red.) For the end of each branch, the two possibilities are:

  • (implicit) permanent red, plain signal or pre-entry signal (handled the same),

  • pre-exit signal or pre-combo signal (handled the same).

If the pre-entry signal finds no pre-exits/combos, the no-exit condition is false, so the signal is green (notwithstanding obstruction). Otherwise, no-exit can only be true if all the found pre-exits/combos are red.

By using a pre-entry with a pre-exit, the train can be forbidden to enter the intervening track if there is another train blocking the first one's egress from the track, even if that other train is not itself between the signals, but just beyond the egress signal, which is therefore red.

This is most useful at stations — bidirectional pre-exits guard each platform, while one or more incoming tracks are guarded by pre-entries, and there are one or more outgoing tracks with plain signals. If all platforms are full, the incoming trains can't enter the critical section of track which the outgoing trains need to reach the outgoing tracks. In that situation, therefore, the outgoing trains have priority over the incoming ones to use the critical section.

Even if trains don't exit the station on the same side, the pre-signals are still useful, as an incoming train defers its choice of platform until one is actually available, rather than picking the wrong one.

Pre-signals are also partially useful on any shared track where routes cross but don't merge or split. One route is controlled by a pre-signal pair over the critical section, so a train won't enter it unless it can get through. For this to work, the egress track must have enough empty tiles (i.e. no signals) to accept the longest train, or else it is not be guaranteed to clear the crossing track.

A plan-view notation

Some pictures, which are based on screenshots from the game, accompany the textual descriptions if you can see them. They are fairly clear, but to aid visibility, a plainer notation is used, and offers a plan view. This also permits new signal types to be represented. The signals appear as follows:

GALLERY( ``plain signal'',,, ``pics/signal-plain.png'', 166,166, ``a green light on top of a red light embedded into the track'', ``pre-entry signal'',,, ``pics/signal-pre-entry.png'', 166,166, ``a green light on top of a red light on top of a black-bordered white circle embedded into the track'', ``pre-exit signal'',,, ``pics/signal-pre-exit.png'', 166,166, ``a green light on top of a red light on top of a black circle embedded into the track'', ``pre-combo signal'',,, ``pics/signal-pre-combo.png'', 166,166, ``a green light on top of a red light on top of a black-bordered half-white circle embedded into the track'', ``permanent-red signal'BR(,,,, `` 'mdash` '')`(to be introduced)'',,, ``pics/signal-red.png'', 166,166, ``a red light embedded into the track'')

Note that, in following diagrams, apparent unidirectional signals will be shown with their implicit permanent reds in the opposite direction. This leaves explicit permanent reds as the only truly unidirectional signals.

NOTE(P(`OPEN`A monochrome notation might fare better when shrunk down to fit a large plan.'CLOSE'))

Signalling enhancements

The current signalling rules are adequate for most tasks, and are probably simple enough to lead to a very efficient implementation (bearing in mind that the program must keep signalling conditions up-to-date as fast as track and signals are laid out). However, there are cases where the signals do not behave intuitively correctly.

Problems with and corrections for obstruction inspection

Plain signals have a small problem when one track crosses another, which crosses yet another, such that the crossings do not permit trains to switch tracks, e.g. at the centre of a tile.

Consider two parallel tracks allowing simultaneous travel in both directions. These are then crossed at right angles by a third track, so we place 6 plain signals around the junction. Clearly, if a train enters on the single track, trains in either direction on the double track must wait until it clears — that works as expected.

Similarly, if a train on the double track enters, the single-track signals should go to red. However, at the same time, the ingress signal on the opposing track will go to red too, blocking any train coming in the opposite direction, even though it is safe to proceed.

For the obstruction condition, the inspection ‘performed’ by the ingress signal on the first track will correctly flood (via a 90° turn) onto the second — any train here is blocking or potentially blocking the first track. However, it then floods onto the third track (by another 90° turn). Any train here is no threat to a train on the first track, so the plain signal is being overly cautious. Obstruction inspection should not go beyond two 90° turns which a train couldn't make. Indeed, we should be able to distinguish three types of track:

  • dangerous track which a train could reach if the ingress signal let it through,

  • dangerous track from which another train could reach the first train's track (but the first train could not reach itself), and

  • safe track from which no train can reach the first train's track.

Problems with and corrections for no-exit inspection

Pre-signals also have an obstruction component, so they suffer similarly from the same flaw, but they have an additional flaw in the no-exit condition.

Consider two unidirectional tracks crossing at right angles. We apply unidirectional signals all round as appropriate, but then make the ingress signals into pre-entries, and the egresses into pre-exits, with the intention of stopping anyone entering the crossing unless they can be sure of exiting, thus avoiding unnecessary blockage of the perpendicular track.

If we assume that there are no trains currently in the junction, the obstruction condition must be false, and we can focus on the no-exit condition. Now suppose that there is a train about to enter the junction, and another ahead on the same track which has just left, but is not yet beyond the next signal, so the signal through which it exited the junction is still on red. If the incoming train enters now, it will be blocked by this signal, and that will block the junction entirely, even though the perpendicular track might still have capacity.

Does the pre-entry signal stop the incoming train because its outgoing signal is on red? No. No-exit inspection is currently the same as obstruction inspection, so both pre-exit signals on the edge of the protected area of track are taken into account — if either of the tracks are free to exit, then the train is let in, even though it cannot reach both of those signals. Even if we use the corrected obstruction inspection for no-exit, the ingress signal would still depend on the egress of the perpendicular track. Therefore, no-exit inspection should be even less extensive than the corrected obstruction inspection — it should not go beyond even a single 90° turn.

A flat, multitrain, 4-way junction

Even if we have corrected obtruction and no-exit inspection rules, we must be careful with our junction design.

Let's start with a simple double-track cross-over, and make all the ingress signals into pre-entries, and all the egresses into pre-exits (and leave enough space after each egress signal to hold a complete train, of course). With our new rules in place, this should work reasonably well: trains from opposite directions should be able to enter simultaneously because their obstruction areas don't overlap; and a train won't enter if its egress is blocked because its pre-entry signal is only looking at the pre-exit dead ahead.

Now let's turn it into a naïve double-track junction by adding some added diagonals.

The diagonals have introduced new routes from the pre-entry to the other pre-exits, so our pre-entry signal will go green if any of the exits are green, even if they are not the ones the train will try to go through. This is reasonable even with the new inspection rules, as the ingress signal cannot know where the train is heading, and we should not expect it to [or maybe we can, with the new signalling expected for 0.6.*?].

We must get the train to indicate its destination to the junction as a whole by giving it a choice of ingress signals. Each incoming route needs a pre-entry for each egress, i.e. 9 pre-entries (if we exclude U-turns). Each pre-entry then has only one route to find an egress – at this point, the decision has already been made – and our new no-exit condition will ensure that only that pre-exit signal is considered. The junction must spread out a bit to fit these extra signals.

We still need only three pre-exits, one for each outgoing route (disregarding the U-turn egress). Each sits on the track just after the points where trains gather onto that line — the obstruction condition will ensure that if any train begins to go to that line, other trains going to the same line will be blocked before they enter the junction risking deadlock.

Explicit permanent-red signals

For any 4-way junction, we can label each pair of tracks line 1, line 2, etc, in a clockwise direction, and consider trains entering from line 1. Then, in our new junction, we'll additionally label each pre-entry signal Nsource-line.destination-line. Finally, we'll label the egresses X1, X2, etc.

Our new junction still has a problem. When a train goes straight-ahead (from N1.3 to X3), it merely crosses over most tracks (so the new obstruction condition doesn't flood to them as far), but it also merges with the track from the right (from N4.3). Even our new obstruction inspection floods onto this track, despite the fact we never intend to go there. The entering train will trigger the obstruction condition for trains in the opposite direction (N3.1 to X1), even though they do not cross.

We might be able to infer from the implicit red at N4.3 on the incoming right-hand track that we will never use it, and so correct our obstruction inspection a little bit more. However, we can't guarantee that a train won't go beyond the merging point, and then be manually turned back. So this is probably not a safe solution, and complicates the inspection computation further.

Instead, let us insert an extra ‘one-way’ signal on the incoming right-hand track, just before it merges with ours between N1.3 and X3. The track opposing us (N3.1 to X1) can now see that we aren't going to cross it, because of the implicit permanent-red signal that would block our path. But this causes another problem — the right-hand track's pre-entry signal (N4.3) cannot see past this new signal to see if the junction egress (X3) is clear. We could make it a pre-combo, but that might result in a train stopping in the middle of the junction.

What if we got rid of this new signal, but retained the permanent red? When the pre-entry signal looks for a pre-exit, it is really looking for a prograde one, to which it can delegate its responsibility for holding back a train from a critical section of track ahead. It won't see the new permanent red, because it is retrograde — facing the wrong way! Yet that red still assures trains from N3.1 to X1 that trains from N1.3 to X3 won't turn back and get in their way.

(Consider a simpler case of two one-way tracks crossing at 90°. After a train has left on one track, what tells a second train waiting to enter on the other track that it is safe to do so? Is it the (apparently unidirectional) egress signal for track of the first train? No – that allowed the first train to leave. It is that egress signal's counterpart, an implicit permanent red on the same tile, which acts as an ingress signal and stops the first train from turning back!)

We need to expand the junction a little more, in order to add our new permanent reds. This also gives us an opportunity to add other perm-reds at critical points, to improve the concurrent flow of trains through the junction.

Note, if might be a good idea to treat an explicit permanent red as a pre-exit. As used so far, it won't make any difference, but it might in other circumstances.

Specification of new inspection rules

How do we specify the step-by-step computation of signalling state such that we incorporate both the new signalling rules and the notion of permanent reds?

To determine the state of a variable signal, we use various forms of inspection along track. The inspection starts on the track under the signal in question, and floods outward to determine the state of the track and signals ahead. The inspection for each signal is independent of any inspection computed for another signal.

Inspection proceeds out of the signal in the prograde direction, i.e. away from the back of the signal, into the next tile, and the next, and so on, as long as the tracks are connected. When a point is encountered, the inspection bifurcates into two or more forks. When a cross-over is encountered with points, the inspection also floods onto that track. When a pure cross-over is encountered, i.e. where a train cannot turn, some flooding may occur, depending on its type. Note that a train is considered to be able to turn 135° indirectly by progressing along the common track a sufficient distance, then changing direction, and progressing down the other.

An inspection has a state which changes spacially as it floods. This state can be distinctly determined as it enters through the side of a tile — an ingress state. Therefore, a tile has upto 4 ingress states. It similarly has four egress states, each of which is independent of the corresponding ingress state at that side of the tile (since they refer to the state of inspection in opposite directions), but is dependent on on the ingress states of the other three sides (subject to the track layout on the tile, and to the type of inspection, as specified below). Each ingress state is simply a copy of the egress state from the corresponding side of the neighbouring tile, or is set by belonging to the tile of the signal affected by this inspection, and by being on the retrogressing side of that signal.

Inspection rules for the obstruction condition

Obstruction-inspection state is labelled either green, blue or black. The initial state is green. When a branch of the inspection flood becomes black, it proceeds no further (i.e. turning black is equivalent to stopping).

Each piece of track across a tile also has a state per affected signal, determined by all the ingress states that affect either of its egress states. If any is green or blue, it is obstructive. Otherwise, it is clear. If any train occupies obstructive track, the obstruction condition is true. If no trains occupy any obstructive track, the condition is false.

(In the notation, when obstruction-inspection state is shown, clear track appears as the normal black. Obstructive track appears as green if either ingress state is green, or blue otherwise.)

Where two tracks with different states cross each other, a train may cross on the clear track without triggering obstruction. (In the notation, this can only be blue track crossing black. If one track were green, the other would have to be blue, so both would be obstructive anyway.)

  1. A green inspection floods as green to all track connected where a train can turn.

  2. A green inspection floods as blue to track connected where a train cannot turn.

  3. A green flood does not proceed beyond a bidirectional signal (including those with implicit permanent reds).

  4. A green inspection floods as blue beyond a prograde permanent-red signal.

  5. A green inspection floods as green beyond a retrograde permanent-red signal.

  6. A blue inspection floods as blue to all track connected where a train can turn.

  7. A blue flood does not proceed to track connected where a train cannot turn.

  8. A blue flood does not proceed beyond a bidirectional signal (including those with implicit permanent reds).

  9. A blue inspection floods as blue beyond a prograde permanent-red signal.

  10. A blue flood does not proceed beyond a retrograde permanent-red signal.

Note that the rules for passing signals can be expressed in an alternative way. Ignore the signal type (permanent red, etc), treat the apparently unidirectional signals as bidirectional, and treat all bidirectional signals as two unidirectional signals back-to-back, infinitecimally separated. A green flood then turns to blue as is passes a prograde signal of any type, and blue turns to black as it passes a retrograde signal. (No change for any other circumstance.) In passing a bidirectional signal, we first pass a prograde signal (guaranteeing that we're no longer green), then a retrograde signal (guaranteeing that we're black). This analysis effectively makes the bidirectional rule given above redundant.

Inspection rules for the no-exit condition

No-exit-inspection state is labelled either red or black. The initial state is red. When a branch of the inspection flood becomes black, it proceeds no further. (i.e. turning black is equivalent to stopping)

Within each tile, each section of track holding a pre-exit or pre-combo signal has a state per affected signal, determined by the ingress states at either end of the track across it. If either ingress state is red, it is considered. Otherwise, it is ignored. The no-exit condition is true if all considered signals are red, and false if any are green.

(In the notation, when no-exit-inspection state is shown, ignored track appears as the normal black, while considered track appears as red.)

  1. A red inspection floods as red to all track connected where a train can turn.

  2. A red flood does not proceed to track connected where a train cannot turn.

  3. A red flood does not proceed beyond a bidirectional signal (including those with implicit permanent reds).

  4. A red flood does not proceed beyond a prograde signal.

  5. A red inspection floods as red beyond a retrograde signal.

Note again that we can the bidirectional-signal rule is redundant if such a signal is considered to be a prograde signal followed instantaneously by a retrograde one.

Observations of the new rules

We can note that we can generate the no-exit state of any given track directly from the computed obstruction state. Simply turn green to red, and blue to black.

Verification of the new inspection rules against a junction

When a train approaches to turn left, it is affected only by other trains already in the junction heading to the same egress.

When a train approaches to go straight ahead, trains heading to its left and entering from its right or ahead of it on the opposing track can prevent it entering, as can any train heading for the same egress. Trains crossing from the left, to the right or to the egress of the track of the incoming train, will also block that train, but it will not have to wait for them to clear the junction completely.

When a train approaches to turn right, it is affected by almost any train crossing or turning right across the centre of the junction, or briefly by any opposing train going to the same junction. However, trains from its left or right, turning left, do not block it.

Note, in all cases, a train does not have to wait for any other train from the same line to clear the junction. As soon as the previous train gets past its ingress signal, another train waiting at one of the other two ingress signals from the same line can enter as well. [This might be a bad thing, as a line might appear to gain ‘momentum’ that prevents other lines emptying into the junction.]

Other uses

Station sponge

A depot can be used next to a station to act as a kind of ‘sponge’, soaking up excess trains as they arrive, rather than having a queue of waiting trains blocking the main line. An arriving train first meets a pre-entry signal (A), which is controlled by the pre-exits on each platform, but an extra one (B) leads to the depot — if all platforms are in use, the incoming train will dive straight into the depot.

Each train waiting in the depot is held back by an implicit pre-entry signal, and follows a track that rejoins the direct link to the platforms. None can leave until a platform becomes available. We must place a pre-combo (C) on the direct line from the ingress to the platforms, at a point between the tracks to and from the depot, otherwise the implicit pre-entries within the depot would be able to see the pre-exit that leads to the depot.

This arrangement is very effective, but still has some problems. In one situation, which we'll call the contention problem, no platforms are initially available, and trains are waiting in the depot. Another train arrives, and passes the pre-entry A, since the track to the depot is available. However, before it reaches the points, a platform becomes available, so it heads for the pre-combo C. Before it gets there, a train rolls out from the depot, and blocks it. The depot train fills the platform, and the just-arrived train is forced to wait until another platform is available, or it turns back and can try the points again. This problem is caused by the pre-combo signal C — it allows a train to leave the depot, even though one might already be heading for the platforms. Yet we can't take C away, as trains in the depot would then be able to ‘see’ the depot ingress signal B, and think they could leave.

The other problem – the servicing problem – occurs at a terminus station. Trains leaving the station might decide to get a service at the sponge depot, hindering the arrival of waiting trains. (It might have been only slightly less convenient to go for some other depot down the egress track.) To stop this, we'd have to place a unidirectional pre-combo on the track exiting the depot (at D), but this would make the contention problem even more likely to occur.

In both cases, we don't really need the pre-combo signals C and D. For the servicing problem, it's the implicit permanent red at D which stops trains returning to the depot, not the ‘back’ of the pre-combo D. And we only have to make it a pre-combo because the internal depot signals need to be able to ‘see’ beyond it to the pre-exits guarding the platforms. If we are allowed to place a genuinely unidirectional explicit permanent red at D, trains in the station won't see the track as a direct route to the depot; plus the depot's internal pre-entries will still be able to see past it.

For the contention between arriving and waiting trains, it's the implicit permanent red with the pre-combo C, not the ‘back’ of the pre-combo itself, that stops the depot signals from ‘seeing’ the depot ingress signal (the pre-exit B). If explicit permanent reds are possible, and our new no-exit condition is in effect, we have no need for the pre-combo, since the pre-signal route from the depot looping round through C and then B would turn from red to black as it passed C.

Unfortunately, this won't work, as the obstruction condition spreads from B as green to the depot, toward the station through D (but stays green), turns back through C (turning blue), and detects the train waiting at B. Deadlock!

The problem now is that the depot uses the same track for both ingress and egress. Maybe this is a case for a depot with separate ingress and egress tracks…? That would probably solve the servicing problem anyway — the depot egress would already forbid trains from the station entering it. On the other hand, it might make the game a bit easy, as you'd effectively have an infinite length of track wound up into one or two tiles.

Ah! But what if you impose a restriction that you cannot have a train entering a depot at the same time as one leaves? That restriction is already implied by the current depots having a shared exit/​entrance. We're separating the two tracks merely to prevent the obstruction condition flooding from one to the other.

Also, if you made one entrance ingress-only, and the other egress-only, you'd need four separate orientations. You could get away with two, if you allowed both entrances to be used bidirectionally, but then allowed the player to add permanent reds (or other signals) either side to allow only one direction each. (This is where it helps to treat a permanent red as a pre-exit – it stops trains leaving.)

Two other possibilities if you don't want through depots:

  1. Don't allow the obstruction condition to flood from the depot ingress track to its egress. Maybe you could require at least one tile of ordinary track beyond the points, before the flood could turn back. The track within the depot would be excluded as ordinary track. — However, this seems a little too exceptional.

  2. Simply make the depot entrace a pre-exit signal – not one that a train can stop at, but which can affect a pre-entry or pre-combo earlier down the line. Our points B, C and D are just permanent reds now, so there's no intervening conditional signal anywhere on the loop, so no chance of deadlock.

Dead-end depot

You can create a dead-end depot with the current signalling system — just use a pre-combo signal in a loop outside the depot.

Where does the new signalling fit in here? Well, it's not much, just a minor simplification. Instead of the loop, simply place a permanent red in front of the depot to allow trains to enter but not to leave. If it is treated as a pre-exit, the implicit pre-entries that control trains leaving the depot will see it, and always be on red.

Implementation

Old rules

Though it has its flaws, the current type of inspection is adequate for most tasks, and it is probably relatively easy to implement. The program merely needs to group several signals together that surround some critical section of track, and detect trains entering or leaving that section, toggling the state of all signals in that group.

A piece of track can only affect one group of signals directly through the obstruction condition. So it only needs to retain one signal-group reference, and that only needs to change when track or signals are added or removed. The whole track can be divided up into neat, non-overlapping sections according to which signal group they affect, and a signal can belong to only one group at a time, so no two signal groups intersect.

For the no-exit condition, a pre-exit signal only needs to refer statically to the one group of pre-entry signals it affects, and the reference only needs to be updated when track or signals are added or removed.

New rules

The new rules can similarly be computed only when track/signals are added/removed. However, there is a fundamental difference in that a signal can belong to multiple groups, and each tile could affect a unique signal group.

There are more data to be considered: the three inspection egress states of each signal at each side of a tile, and the overall state of the tile (or two states at a pure cross-over). (Ingress states are just copies of egress states, so should not need to actually be stored separately.) We can reduce the number of signals to be considered by not keeping records of signals which are not affected by the track, i.e. only hold local data, and infer the rest of the information by its absence.

We could arrange for each track egress point to record several sets of signal references which it affects. Since there are 3 states for obstruction, and 2 independently for no-exit, that's 6 distinct aggregate states. One of these is black in both, and so refers to unaffected signals, which we can ignore since the information isn't propagated — leaving a sequence of 5 sets. Taking the no-exit states black and red as 0 and 1, and the obstruction states black, blue and green as 0, 1 and 2, we can multiply the no-exit state by 3, add the obstruction state, and subtract 1 to get the position (from 0) in the sequence. As track or signals are added or removed, propagated egress-state changes manifest as signal references moving between these sets.

It might be possible to exploit the similarity between the red-black distinction of no-exit inspection and the green-blue/black distinction of obstruction inspection. That is, take each of the figures depicting green flooding for obstruction, and change green to red and blue to black, and you should get the same figures as flooding for no-exit. This would reduce the number of sets required at each tile egress to 2, red-green and blue

The signal also needs to keep count of the number of train-occupied tiles that affect its state. The obstruction condition is true if and only if this count is non-zero. When a train enters or leaves an affective tile, that count goes up or down. It may also change when track or signals are added or removed, propagating an egress-state change that includes or excludes some occupied track.

Summary

(Not all necessarily verified, but at least suspected:)

  • All of the current signals are bidirectional. Even the ones which appear to be unidirectional behave as if the other – invisible – signal is an implicit permanent red.

  • The rules which determine the obstruction area (the area of track which, if occupied by a train, causes a given signal to go red) could be made more strict (so the obstruction area could be smaller). Specifically, the area covers only routes from the signal which do not turn through more than one 90° cross-over.

  • The rules which determine the pre-exit set (the set of pre-signal egresses which affect a given pre-signal entry) could be made more strict (so the pre-exit set could be smaller). Specifically, routes from the entry to the exits would not turn through any 90° cross-over.

  • Smaller obstruction areas and pre-exit sets allow for more compact, level, multitrain junctions.

  • Explicit permanent reds, which are truly unidirectional, could be useful in certain junctions, ones with 90° cross-overs, such as those which exploit the modified signalling rules.

  • Consistent (and fairly simple) rules can be devised to incorporate the behaviour for all three changes (obstruction area, pre-exit set and permanent reds).

  • Changes to the signalling shouldn't affect junctions which already work, only those where the signal arrangement would have previously been considered faulty.

  • The new computation of the obstruction area incorporates the new computation of the pre-exit set.

Caveats

  • The new junction isn't as compact as it might appear. For each pre-exit to work, there needs to be sufficient unsignalled track for the longest train just beyond it. This will force trains to space out and reduce throughput.

    It could be improved slightly by (say) tripling the egress track, with (bidirectional?) pre-exits on each one, and turning the pre-exit into a pre-combo (or removing it). You could also add a depot guarded by a bidi pre-combo to give ‘infinite’ capacity.

  • A train waiting to turn right has to wait for so many occillating conditions to converge that it might never be able to enter.