Bay 12 Games Forum

Please login or register.

Login with username, password and session length
Advanced search  

Author Topic: The automatic minecart route switch, an exercise in dwarven engineering  (Read 1441 times)

Larix

  • Bay Watcher
    • View Profile

When building minecart tracks for distributing goods, one might sometimes want to route several lines across a common rail track. The problem then is separating the carts again so they go to their designated targets. There are of course several options, e.g. enabling the needed switches directly before giving the depart order, or using carts of measurably different weights, but since i found that minecarts follow exact build order rules to devolve their movements, i was sure carts' ages could be used as switch argument.

It wasn't easy, but i succeeded: one cart of four can be sent over a track into the switching array, and it'll be sent to the correct one of four destination bays, all through the magic of synchronised collisions.

Spoiler: large tangle of track (click to show/hide)

How does it actually work?
First of all, we need a proper collision: two carts must try to move in a way that conflicts with the other's movement, _in the same game step_. In each such collision, the older cart will take its move first. If two carts are immediately adjacent and basically try to move into each other's location, this means that the older cart will push the younger cart. The enter movement pulse of the older cart will pass to the younger. The younger cart moves away from the collision, the older cart comes to rest in the location it reached before the collision.

   
Paths only to the left, relevant buildings for the collision to the right.

The "traffic" cart that's to be switched enters from the right. It's coming in very quickly in the given system, somewhere around 80.000 speed, gets stopped and turned around by a highest-speed roller, setting speed in the switch itself to 50.000. When it passes over the pressure plate next to the roller, the plate activates the (also highest-speed) roller to the left, where the resident switch-"operator" cart sits and opens the door right to the south of it. This accelerates the operator cart to highest-roller speed and lets it out onto the collision track, facing the traffic cart.

The collision is fully synchronous and thus the older cart will come to rest in the middle of the collision track, while the younger cart moves off. In the switches i built, the traffic cart has reached its destination when it stops, if it's "too young" yet, it gets pushed off to the east, around the corner and to the next switch cell. It gets accelerated quite a lot on those impulse ramps, because that helps with ensuring a regular speed from the next roller.

Obviously, the resting cart also needs to be moved out of the way; it wouldn't be much of an automatic switch if every switching operation would require a dwarven vehicle hauling job for cleanup. How to do this? Why, with two more rollers, of course:

In the middle of the collision track, over the two possible stop locations, there are two single-tile rollers, the one to the left pushes the operator cart west, the one to the right pushes the traffic cart to its destination path south. The cart that gets sent out from the collision will always move over a pressure plate actually switching these rollers on. They're off otherwise (they must be off so the carts can actually cross them to collide). The plate crossed by the operator cart _also_ toggles the gear connecting its "home" roller: it gets engaged by the traffic cart and would stay on for 100 steps otherwise, sending the operator cart around repeatedly. One hundred steps later, when the traffic cart's plate resets, the roller turns on again, but at the same time the door closes, so the cart can't move anyway.

For the scheme to work with four routes/carts, three cells are needed and the seven carts must be built in the order
T1
O1
T2
O2
T3
O3
T4

Cart weights should not affect the ability of the switches to tell carts apart, but the output speeds of the collision can vary a lot when different-weight carts collide. To avoid misdirected traffic and derailings, the operator carts should be much heavier than the traffic carts (more than twice as heavy), which means pushed operator carts will move extremely slowly, if at all. I built it all with absolutely same-weight carts (all made from bayberry wood) which completely removed that concern, but that's obviously not an option for material transport routes.

I had to put three medium-friction track stops into the third switch cell and needed to build a corner into the second cell's destination route (seen in the pictures) because for some unfathomable reason the N->S roller gave the (presumably) resting cart a minimally diagonal push (but only in this cell, not in the others). This was likely all caused by letting carts run into working rollers full-throttle, resulting in weird distance offsets.

Actually getting the construction right with such a "just passing through" cart is quite tricky, because carts still calculate distances normally when moving over rollers; a wrong setup can give you impractically slow carts (much slower than the roller set speed) or errors caused by incompatible distance off-sets on the collision rail, where one cart invariably ends up a full step ahead of the other, so the collision's no longer synchronous. For an easier approach, the traffic cart should be fully stopped before being sent onto the collision rail, e.g. by temporarily switching off the incoming roller and letting the cart run into a wall behind it. That fully zeroes speed and apparently normalises position to the middle of the tile.
Logged

Larix

  • Bay Watcher
    • View Profile

I came back to the basic idea time and again. Making a "sort by age" switch that doesn't use power shouldn't be too difficult using pressure plates and buildings, but what interested me most was the idea of a signal-less age-sorter. After a bunch of tests kept failing, i finally understood the problem in the basic setup of

- cart A (to "measure") pushes cart B (reference; A is either older or newer than B, this age difference should produce different outputs).
- cart A bounces back on ramps
- both collide while on ramps

This simple setup doesn't work for a fundamental reason:
- cart B starts moving earlier or later, depending on whether it's older or newer than cart A. If B is newer, it will start moving on the turn it gets pushed, if it's older, it'll start one turn later. That's because oldest carts take their moves first. If an older cart gets pushed by a newer cart, it has already taken its move (of standing still) and must wait until the next game step to react to the push.
- in a collision, the fact that older carts move first exactly neutralises the timing difference produced in the initial push.
There may be ways around the issue, probably with extreme speeds, but in my lowish-speed tests (required when working with loaded carts, which i'm most interested in) i found no way to get an output difference when working with that basic setup.

The solution: use a setup that doesn't produce the timing divergence at the push. How? By a transmission cart:

Code: [Select]
═ST▼▼═M

"M"easurement cart shall be tested on age vs. "S"cale cart. It gets pushed west, goes through the double-ramp, pushes the cart just outside the pit and rolls back down the ramp inside the pit, returning east. To avoid time divergence at the push, it doesn't push the scale cart directly, but sends the pulse through the "T"ransmission cart, a cart that's  older/younger than _all_ to-measure carts (in my test, it's younger). No matter how old the measurement cart is relative to the scale cart, the transmission cart always starts moving at the same time and since the timing of the push transmission to the scale cart only depends on whether the scale cart is older/younger than the _transmission_ one, there's no temporal divergence possible here, either.
Result: the "S"cale cart starts moving on the same step regardless of measurement taken, build order only makes a difference in the actual collision. There, the older cart moves first and with the proper layout, different outputs result.

No screenshots, because there's nothing obvious to see. Of interest may be the collision track:
Code: [Select]
complicated, well-behaved:
   .##.
#▲╔▲▲▲▲╗▲#
  ║#║║#║
ramps

   .##.
#═╔║║║║╗═#
  ║#║║#║
track

simple, but harder to regulate:
  ##
#▲▲▲▲#
  ║║
ramps

  ##
#═║║═#
  ║║
track

One cart comes from the east, the other from the west, both from above. They need to move sufficiently simultaneously to end up on the middle pair of ramps, both trying to move into the other cart's place on the next step. At that point, build order decides which cart moves first - it pushes the other one, transmitting its movement pulse to it and stops completely on its current tile. Since that is a ramp tile, it just rolls off it. The pushed cart gets enough momentum to roll across the ramp it stood on, over the adjacent one and back to the track corner on flat floor (or up and out of the pit).
If the measurement cart is older than the scale cart, it comes to a rest on the middle ramp and rolls off that, if it's newer, it gets pushed back and takes the "distant path". Similarly, the scale cart takes either the outer or the central path, but we'd usually just funnel it back to its original location so it can be used for the next measurement.

I used the larger collision track design for the main test. The simpler design works, too, but it's quite a bit more demanding regarding incoming carts' sub-coordinates and speed.

PS: the first working design actually had the measurement cart push _two_ other carts in succession, a "baseline" (newer than every other involved cart) in addition to the "scale" cart (either older or newer than the measurement cart, thus gets going sooner or later). Movement order between scale and baseline cart is invariable, thus push divergence can be converted into output difference. While monstrously impractical, it was a vital step towards getting the proper solution above (removing push divergence so that move order in collision is the only variable).

PPS Why bother?

Can't we just pick carts of different weights and let calibrated pressure plates do the work?

Yes, if we're working with carts that are either empty or are loaded with well-known weights. But if we have, say, a cart loaded with crafts, weight depends on the materials used - cobaltite crafts are much heavier than diorite ones. Cart weight can become an unreliable parameter. But all carts have a definite position in build order, and age-sorting can theoretically precisely identify _every_ cart, regardless of current load. Age-sorting can tell carts apart that have the exact same weight; in fact, it can differentiate between carts of the same material and quality. You could make an utterly evil puzzle that requires bringing ten *oaken minecarts* in the correct order...
« Last Edit: July 08, 2015, 03:46:15 pm by Larix »
Logged

Ravendarksky

  • Bay Watcher
    • View Profile
    • DFMon.exe - Get rid of DF SPAM

This is crazy! I love it!

I'd have been doing something clandestine with timer tracks which switch the track just as a minecart gets to the end of the common track and a processing loop which prevents more than one cart from every getting there within the same switching period but this is 100% better.

How on earth did you ever discover that build order determines movement priority when collisions occur?

Am I correct that this only ever lets you have two routes with one switch? I guess you could just have multiple transmission minecarts in a larger version of the switch to keep filtering the end route? I must admit that I am not fully understanding how the end goal of one track to many minecarts is reached, although I can see quite clearly how two minecarts are separated.
Logged

Larix

  • Bay Watcher
    • View Profile

Build order plays a role in precise timing (it was a pretty big issue when the first true 100-step repeater in pure fluid/mechanic logic was built). It sort of made sense that it'd influence minecart behaviour. Verifying the hunch took some fiddling and coming up with circuits that actually make use of these fraction-of-a-tick differences was the harder part.

And yes, such a switch by itself is just binary - either the tested cart is older or newer than the scale cart. You could come up with sillier stuff like switching roles - in some case, the tested cart is made the new scale cart against which the next incoming cart is tested, while the original scale cart is extracted. That could be used for longer cart-sorting schemes, but that'd be a pure dwarfputing application, not something for transportation schemes.

If i ever decided to use such a thing in a transport network, i'd probably use one of the concepts with signals. Collisions can lead to speed changes, which don't agree with the very tight timing required.

PS: and what i like most is the preposterous premise: Urist, you see two minecarts. They are _somehow_ different, although they look exactly the same, weigh the same, cost the same... How do you tell them apart?
Answer: bash them together in an absurdly specific way. Obviously.
« Last Edit: July 09, 2015, 10:47:43 am by Larix »
Logged