Heavily insane sounding (and actually insane) concept ahead. Please proceed with caution.
When I first came on the 1.8 server, I began experimenting with a seamlessly working 'rising bridge', so to say - which in concept first was a three block deep pit with a lever extending a bridge in front of the door. The concept does sound simple enough - stack three sticky pistons on each other with a block on top of it and connect their predicted positions with redstone...
...Nope. Piston physics are a bit more complicated and unintuitive than that.
The first discovery I made was that you cannot push or pull extended pistons due to the way the engine works, but to even further complicate things, upon pulling back sticky pistons, the block on top of the piston being pulled isn't pulled back either. After a long time of figuring this out, I came up with an ordered list of actions for extending and retracting this bridge. Assume that the pistons are labelled, from bottom to top pistons A, B, and C. Obviously, this is for working with blocks unaffected by gravity, such as cobblestone.
For extending, it's rather simple:
Code: Select all
Extend piston A
Extend piston B
Extend piston C
Now, retracting is where it becomes a horrible headache to even attempt to complete this construct:
Code: Select all
Retract piston C
Retract piston B <- Piston C gets pulled back, the block stays afloat
Extend piston C
Retract piston C <- The block gets pulled back
Retract piston A <- Piston B gets pulled back, piston C stays afloat with the block on top
Extend piston B
Retract piston B <- Piston C gets pulled back, the block stays afloat
Extend piston C
Retract piston C <- Every block returns to its original position
Note that this sequence hasn't been tested live, simply because it's a mess, something you probably can't even do with two, let alone four "piston towers" placed below each other. As you may note, for N pistons, it takes N steps to extend and N*N steps to retract, therefore the complexity of the system is quadratically proportional to the amount of pistons vertically stacked.
I decided to simplify the construct to a two blocks deep hole, therefore requiring only two pistons to work in a sequence. At first, to the naked eye, this appeared to be a two output level (as in, you have to provide output to the pistons on two different heights) problem, and I began to work with this assumption, just to see it fail as you probably could see it on the map if we could successfully restore it.
For retracting two pistons, the sequence is a bit easier: (assuming the bottom piston is A, and the top piston is B)
Code: Select all
Retract piston B
Retract piston A
Extend piston B
Retract piston B
After large stack of failed drafts (yes, I actually have at least 30 pieces of paper scattered on my desk describing circuits attempting to do this), I realized two very important things:
First off, output must be provided to the pistons on three levels, as the upper piston will be in an intermediate area when it needs to pull the block back. This realization finally made me able to describe the entire system with a finite state machine. For those who don't know this term, a finite state machine is an arbitrary mechanism that stores its current state and shifts its state depending on the input provided to it while providing the output specified to another, arbitrary mechanism.
The following diagram illustrates the way a two piston bridge will work properly. Explanation is provided below the diagram.
Code: Select all
0/000
,-, ,----,
| v 1/10X X/1X1 v | 1/1X1
Strt --------> ExtB -------> BrUp --'
^ |
| X/000 | 0/1X0
| v
RetB <-------- ReXB <------- RetA
X/010 X/000
A bit of explanation then. The four characters (such as Strt) are the names of the state, this is really the least important part. The arrows are state transitions, from the source state to the destination state (the pointy end, duh). Now, the state transition arrows have a five-character code next to them, #/###. The part before the slash is the input provided for the state transition - if the input is 0, the state transition with the '0/' part will happen, if the input is 1, the state transition with the '1/' part will happen. Obviously, 0 means the redstone input is off, and 1 means the input is on - the input is the result of logical arithmetics applied to any number of power sources, such as, if there is a lever L and a pressure plate P, and the input is active if either one of these is active, then the input is "L OR P". If the input is marked with an X (called, literally, in the trade as "Don't care"), then the transition will happen after some delay regardless of input. As the diagram shows, there are two stable states, Strt is the input is 0 (the bridge is constantly inactive), and the BrUp if the input is 1 (the bridge is constantly active), both of these are knocked out of state if the input changes at some point, ie. the lever is pulled. The part after the slash is the output - I have assigned three bits to the different output levels, here the three bits define the state of the three output levels from the lowest one to the highest, this will be explained in a moment. The value X in the output means the bit in that position may be either 0 or 1, as it doesn't affect the transitions at the current point.
The second realization I came to is that pistons need not be powered directly - if a piston is placed face-adjacent to a powered block, the piston itself will be powered by the block. This mechanic makes it easier tenfold to actually construct such a contraption. Below is a side-view diagram of the placement for one such 2-high piston tower.
Code: Select all
X X . X
B B . B
B B X 3
B B P 2
B B P 1
On this diagram, . represents air, B represents an arbitrary block, P represents a sticky piston, T represents an arm extended by a piston, X represents the bridge's pieces, and 1, 2, 3 represent blocks which we consider the output levels - so if the output provided by the finite state machine is 101, that means blocks 1 and 3 are powered and 2 is not, which results in:
Code: Select all
X X X X
B B T B
B B P 3
B B T 2
B B P 1
The finite state machine itself is simple enough to realize in an electrical circuit, if we number the states from 0 to 5 starting from Strt and heading in a clockwise order. (Therefore, Strt is state 0, ExtB is state 1, and so on...)

What you see on this diagram is representing this finite state machine. The three small things labelled "D" on the left are D flip-flops (you may laugh now), which are capable of storing 1 bit of data. D flip-flops store whatever value is on the D input on the positive edge (a 'positive edge' is the moment in time when a certain variable changes from 0 to 1) of the clock input and start provide the same data on the Q output until the next positive edge of the clock input. The three of those together store the ID of the current state, from 000 (state 0, Strt) through 101 (RetB). The big thing on the right is a ROM with four pins on the left - these are the addressing pins, used to tell the ROM that which address should it extract data from to send to the output, and eight pins on the right - these are the data output pins. The address input for the ROM consists of four bits. The most significant bit, A3, is connected to the input, and A2 through A0 are connected to the registers storing the current state. This way, if the input is 1 and the current state is Strt, the data at address 1000 will be sent to the output. On this address we store 8 bits of data. The two MSBs, D7 and D6 are insignificant. On D5 through D3, we store the ID of the next state, in the current case, 001, and on D2 though D0 we store the actual output the state transition should trigger, which is 100 or 101.
In theory, and electrical engineering, this is an near-optimal solution to this finite state machine (although, since states are consecutive, it would be more optimal to use a counter with an enabling signal). However, we're talking Minecraft here, and in Minecraft, this isn't a simple construct.
Therefore, the construct must be simplified.
In comes an excellent thing which is much harder to represent in combinational circuits, but easy to create and use in Minecraft: Delays. The finite state machine can be simplified by replacing state transitions with delaying. The replacements are even too mind-boggling for me to document, if you are interested how I came to this conclusion, do ask, and I will tell, but I'll probably stop semi-wasting forum space now.
After two days of work, I present you the much less scientific way of creating a two blocks high piston tower which nearly seamlessly raises a block by two and retracts it correctly.
Code: Select all
1. Place two sticky pistons on top of each other and a block on top of them.
2. Place three blocks on top of each other next to the pistons, in a manner that the bottom block is adjacent to the bottom piston. From now on, I will refer to the bottom block as A, the middle block as B and the top block as C.
3. Create an input stream. This may draw power from any power source, such as a lever.
4. Separate the input stream into three different streams, make sure the wires do not touch.
5. On one of the streams, place a very short delay, and make sure it powers block C.
6. On another stream, make a longer delay, and connect it to block A.
7. Construct an AND gate separately. I will refer to this as gate D.
8. Construct an XOR gate separately. I will refer to this as gate E.
9. Construct a NOT gate separately. I will refer to this as gate F.
10. Create a fork in the third stream. Connect one fork endpoint to the input of gate F, and delay the other fork endpoint by a longer time than the delay is for block A.
11. Create a fork in the stream you just delayed. Connect one fork endpoint to one of the inputs of gate E. Further delay the other fork endpoint by a reasonable amount of time and connect this to the other input of gate E.
12. Connect the outputs of gate E and gate F to the inputs of gate D.
13. Connect the output of gate D to block B.
In theory, the following happens here, assuming I is the original input:
Upon a change from 0 to 1 on the input, the charge first reaches C, but nothing happens. Then, the charge reaches A, thereby activating the lower piston, placing the upper piston next to C, and therefore activating it.
Upon a change from 1 to 0 on the input, the charge first disappears from C, retracting the upper piston. Then, the charge disappears from A, retracting the lower piston. Then, the shorter delay input reaches the XOR gate. If we name the inputs on a XOR gate X1 and X2, we can say that the output of the XOR gate will be 1 if and only if X1 does not equal X2. Now, if the charge reaches one of the inputs before the other one, obviously, the two inputs will not be equal, and the output of the XOR gate will be 1, generating an impulse until the charge reaches the other input. This short charge will reach the AND gate, whose other input is the negated I, which in this case is 1. Since both inputs on the AND gate are 1, for the duration of the XOR gate's impulse, block B will be powered, therefore extending and immediately afterwards retracting the upper piston. This sequence corresponds entirely to the one described above.
In the end, you should have the following circuit in redstone:

If it doesn't work try increasing the delay time gaps a bit.
I hope you found this little essay interesting, have fun with your extending bridges... if you still think you want to build them.
A little note, this works not only vertically, but horizontally as well.
PS. Yes, this is why I'm not going anywhere with Trevor right now, because I apparently have a serious case of OCD.