Principles of Goblin Logic

I use goblins (or elves-- they both work) for my logic designs. There are a number of reasons for this:

1. Goblins don't die of old age
2. Goblins don't have babies
3. Goblins don't need to eat, drink, or sleep
4. Goblins don't need "citizens trigger" pressure plates (which leads to build hell)
5. Goblins are readily available, in huge quantities, on almost all maps
6. Goblins path predictably to map edge (after capture, at least)

I avoid mounts and other invader animals. I have had bad luck with them, and any tightly closed door breaks path.

Goblin Pathing

I said that goblins path predictably. This is true so long as the goblin has one and only one path to the map edge.

That requires some explanation. It's fine if multiple paths exist, so long as all paths lead through the same next tile. As soon as multiple tiles exist from which a goblin can escape to the map edge, we no longer have predictability.

Unfortunately, manipulation of path length doesn't help.

This leads to our basic three rules of goblin logic:

1. Goblins will only be allowed to move if they have one and only path
2. Goblins without a path will be constrained to a single tile
3. There must always exist a path to the map edge from any logic circuit we build

Map Edge

The fact that goblins require a map edge for predictable motion does not mean that we can't wall up our fortress! There are a number of ways around this. We can build our logic circuits separate from our main fortress; we can have a bridged connection, such that goblin logic paths through the fortress normally, but through an alternative path when we wall up.

We can even connect our logic to the underground (not recommended, and not tested), or over a bridge 10 z-levels above the ground to the map edge (tested, and very safe).

Probably the safest way to run goblin logic is through a tightly closed artifact hatch leading to the surface. Building destroyers will not path through it, nor will they be able to break it. Creatures will not be able to pass it, but goblins will. Most or all creatures that will path to a goblin to kill it are either building destroyers or undead animals. No guarantees, though-- haven't tested everything.

The rules

AND gate

Consider an AND gate.

```####
gDD^
####
```

g is goblin, D is door operated by mechanism, ^ is a pressure plate, # is a wall.

The goblin must make it through two doors to hit the pressure plate. The doors are opened by some sort of memory cell, such that if P1 is true, the left door is open.

What happens when P2 is true but not P1? No path.

But what happens when P1 is true but not P2? No path-- but the goblin may still wander into the space occupied by the left door. If our situation changes, say, such that P1 becomes false and P2 becomes true, the goblin will have a path, despite falsity of P1 AND P2.

This is because we forgot one of our rules: if there is no path, constrain the goblin to a single tile.

```#####
g.DD^
#####
```

. is hatch over channel, triggered by mechanism, currently open

Now, we don't constantly evaluate the truth of P1 AND P2-- we only evaluate when neither P1 nor P2 are in the process of change. We specify when to evaluate this by sending a close signal to the hatch. If P1 AND P2, the goblin triggers the pressure plate. Otherwise he doesn't.

But if P1 is false, the goblin can still block off the door, the same as before. We need to send a null path, so that the goblin, when triggered, definitively returns true or false.

NAND gate

```########
^h.g.DD^
#h######
###
```

h is hatch, triggered by mechanism

Now, we send close signals to the hatches on either side of the goblin. When we do so, the goblin paths predictably to one side or the other, and doesn't dawdle anyplace. This is because we've added a NAND gate to the left of our goblin. Anytime an AND is true, a NAND is false, and vice versa.

NOR gate and OR gate

I'm just going to show you these last two gates, because we can do any logical operation with NOR and NAND. You don't need any other gates. I'll show a simple OR, just because it's the opposite of NOR-- that is, if NOR is true, OR is false, and vice versa.

```########
^hh.g.d^
######d#
########
```

That's it. Those are all the logical operators you need. (I'll probably point some others out anyways.)

You might notice that all of the designs so far are single use. We have to load them with a new goblin every time we use them. We don't want that. Here's a NOR/OR expanded to show how we're going to do that.

```############
<h^hh.g.d^h<
########d###
############
```

< is upstairs, pathing to map edge

All that we've done is add a hatch cover and a path to map edge. The peripheral hatch covers are each linked to the adjacent pressure plate. When the goblin arrives at either NOR or OR, the hatch opens, and his path to the map edge is blocked. There's one problem: at that point the goblin has no path, and so he won't path predictably. But we can fix that:

```######<#####
######.#####
######g#####
<h^hh.#.d^h<
########d###
############
```

By now, maybe you realize why the hatches next to the goblin are open: it's because he's standing on a pressure plate that, like all of our pressure plates, triggers the adjacent hatches. Let's draw the same picture, but with no goblin:

```######<#####
######h#####
######^#####
<h^hhh#hd^h<
########d###
############
```

Let's define a term: the goblin's position after running one of these tests is his reset position.

I want to point out one problem with this design as shown. Remember how I said that the goblin needs to always have one and only one path, or be constrained to a single tile? Here, after he evaluates NOR/OR, he has no path until his hatch opens-- which will occur after his evaluation. That makes his behavior unpredictable-- for instance, we can't be sure that a CLOSE will rapidly follow his evaluation. It's not a huge problem, but it's one we want to avoid.

Signal types

I mentioned how we were going to prompt the goblin to choose a path before-- we were going to send a close signal to the hatches adjacent to him. (Obviously, we won't want to send a close to the hatch preventing his escape to map edge though.) But sending close signals is easier said that done. Our pressure plates send opens when activated, and closes ~100 ticks after deactivation. We have a few choices. Consider:

```###
#l^
###
```

l is lever, ^ is citizens trigger pressure plate

This is our basic input. The lever is linked to nothing-- its only purpose is to get a dwarf to run across the pressure plate. In this case, our pressure plate should be linked to the two hatches permitting our goblin to choose NOR or OR. The dwarf runs across the pressure plate, opening the hatches-- but they're already open. 100 ticks later, it sends a close signal to both hatches, which close, opening path to our goblin. Let's define a term: this kind of a signal, a rapid OPEN-CLOSE, is a trip.

But what if our goblin isn't in the proper position? What if he's currently running a test? Those hatches won't be open, and opening them will block his return to reset. That's not a big problem in this simple circuit, but we want to avoid it in general.

```####
#l^d
####
```

All we've done is add a door, and linked the pressure plate at reset to this door. Now, the door doesn't permit tripping unless the goblin is at reset.

Except that's not quite true. The door will be open 100 ticks after the goblin leaves reset. A small revision:

```############
#l^        d
############

```

Not perfect, but it works.

Of course, we don't want things to be run by dwarves. We want complicated logic circuits involving the interplay of multiple goblins.

Long paths

This should look familiar:

```            ######<#####
######h#####
##################^#####
#<h^           hhh#hd^h<
####################d###
############
############
```

It's just our trip lever hooked up to our NOR/OR. Imagine a few of these in operation, with the NOR end tripping the reset hatches of the next. You can see that it won't be a huge problem to run trips from goblins instead of dwarves.

But there is a very large problem with this circuit. The hatch granting reset path will close before the goblin reaches our NOR pressure plate. There is a risk that our goblin will just run half-way to NOR, then back to reset, without triggering anything.

```            #######<####
#######d####
#######h####
###################^####
#<h^           hhh#hd^h<
#####################d##
############
```

Now we've added a door to the reset path, triggered by reset position. This door will close at the exact same time as the hatch, so we block reset path. But we still have the problem of getting the goblin to reset, because now no path exists, and even if one did, we have the risk of the goblin oscillating around the NOR path. We could build a complicated ground path to drag the goblin around. But instead, let's try something much more general purpose.

```  ##################<#
##               h#h#
#d################^#####
##^           hhdh#hd^h<
#h##################d###
#<#                ###
```

Let's trace it through. Hatches are tripped, goblin heads to NOR. Hatch to reset path closes at the same time as door to reset path closes, no path. Goblin continues to NOR, trips NOR. Hatch blocks NOR path. Door opens, permitting return to reset.

You might think that there's no room to make a similar loop for OR, but that's not true. We can hook it into the same return to reset arm.

```                  #####
##   ##
## ### #
############### ##<# ##
##               h#h## ##
#d################^####d#
##^           hhdh#hdd^##
#h###################d#h#
#<#                 ###<#
```

There's got to be something more elegant, right? There is.

```<        <
h########h
#^hd   h^#
#h######h#
# #    #d#
# #    # #
# #    # #
# #    # #
#d#    # #
#h######h#
#^h   dh^#
h########h
<        <
```

Each pressure plate is linked to the adjacent hatches and the nearby door. Arrival at one permits continuation along the loop, as controlled by other devices. We don't actually need four arms, but it makes it pretty. Each arm contains an operation that we trip along the way. Each of the 4 pressure plates in the corner is a reset. We cause an operation by tripping the hatch clockwise of each pressure plate (we can trip all 4 at once safely, don't worry).

Here's what a NOR/OR arm might look like:

```    ###
<  ##d##  <
h### d^###h
#^hd### h^#
#h##hh^##h#
# #######d#
```

We could build further operations into additional arms, but the next arm doesn't actually have to perform any operation. Consider the following:

```    ###
<  ##d## <
h### d^##h
#^hd###h^#
#h##hh^#d#
## ##### #
###     ##
#######
```

This is a functional, return to reset NOR/OR, that operates reliably for goblins of any movement speed, and returns goblins to the original position. It follows our rules: a goblin either has 1 and only 1 path, or is on a single tile. It returns a true or a false (although we can safely ignore the false, if we don't care) in the form of a trip-signal-- which is the same kind of signal that starts this device. Given equally fast goblins, two of these could trip each other, although that would be pointless.

Since the second arm of our loop does nothing, and doesn't even need a trip for the goblin to path down it, let's call the rightmost path to surface the completion point.

There's only one thing to be careful of, and that's making it too small or making it run too frequently. Return of goblin to reset does not mean the entire circuit is reset yet! We need to give time for the hatches by completion to close before making another run through the circuit. Ideally, no circuit should be repeated until 100 ticks from the time that the goblin has returned to reset; for one arm loops like this, it's good enough that the circuit not be run again until 100 ticks after leaving the completion point. Notice one thing-- running the completion point generates a trip signal itself, that doesn't send a close for 100 ticks. Linking the completion point to the start hatch ensures running this circuit as frequently as it can be run. (Not that we want that. We need time to be able to write to memory.)

In larger loop, all we need to be careful of is that we don't run the operation again until goblin has returned to reset position.

Any further discussion is going to get hopelessly complicated if you don't understand this basic loop. There is an operation, and there is infrastructure, and you need to know which is which. Our infrastructure is never going to change, but our operations are, and mostly, I'm not going to show you infrastructure again.

Infrastructure

Infrastructure is only ever linked to from within the circuit itself, with one exception (the begin hatch) which is linked to plates both inside and outside of the circuit.

Pressure plates: The leftmost pressure plate is reset position: it lets us know the operation is ready to be run again. The rightmost pressure plate is completion point: it serves an infrastructure purpose, and if we want to, it can let us know the operation has been completed.

Hatches: The hatches adjacent to reset position and to completion point are infrastructure. Infrastructure hatches are linked to adjacent pressure plates. They limit movement through the operation. The hatch immediately to the right of reset is a special hatch: tripping this one begins the operation. We'll call this special hatch 'begin.' Other than begin, no hatches are linked to anything except the adjacent, infrastructural pressure plates.

Doors: The door just to the right of begin, and the door one tile south of completion, are infrastructural doors. They are linked to reset and completion respectively, and block retrograde pathing for long loops.

Operations

Operation structures are only ever linked to from outside of the circuit.

Doors: The two doors in the middle, on the uppermost arm, are operations doors. Their layout forms an OR decision.

Hatches: The two hatches in the middle, in the arm just below the OR decision, are operations hatches. Their layout forms a NOR decision.

Goblin memory and more signal management

But what sets the doors and hatches that constitute evaluation of NOR/OR? Obviously, we can't set them with a trip signal.

```########
<h^hh^h<
########
```

Hopefully, if you've followed me so far, I don't have to explain the above. Each pressure plate is linked to the immediately adjacent hatch.

This is our crudest form of goblin-based memory. One or more of our pressure plates is linked to comparison doors and hatches. To toggle our memory state, we send a trip signal to the two middle hatches.

For an example circuit, consider two memory cells and our NOR/OR. The rightmost pressure plate of each cell is linked up to one of the doors and hatches in the center of our NOR/OR. We'll call this rightmost value '1'. Our OR arm trips the central hatches on memory circuit 1. We run the operation, to begin with, by tripping the hatch clockwise of reset.

What happens?

```Memory a is 1, memory b is 1: Memory a becomes 0.
Memory a is 0, memory b is 1: Memory a becomes 1.
Memory a is 1, memory b is 0: Memory a becomes 0.
Memory a is 0, memory b is 0: No change to memory.
```

This is a fun demonstration, but you can see that we want more features than just toggling our memory. We want the ability to set memory to a certain value.

```  ###
###d####
<h^hh^h<
####d###
###
```

This is our settable memory. Let's change it so that instead of linking OR to the hatches, we link it to uppermost door.

```Memory a is 1, memory b is 1: Memory a becomes 0.
Memory a is 0, memory b is 1: No change to memory.
Memory a is 1, memory b is 0: Memory a becomes 0.
Memory a is 0, memory b is 0: No change to memory.
```

Or we link it to the southermost door:

```Memory a is 1, memory b is 1: Memory a becomes 1.
Memory a is 0, memory b is 1: No change to memory.
Memory a is 1, memory b is 0: Memory a becomes 1.
Memory a is 0, memory b is 0: No change to memory.
```

You might also notice that this memory forms a loop-- just as we settled on for our NOR/OR. A goblin running between the two pressure plates always runs in a certain direction, and steps on each tile of the loop exactly once. All good goblin design forms loops like this. Notice, too, that it follows our rules: so long as we write to it no more frequently than every 100 ticks, our goblin always has one and only one path, or is standing on a single tile.

(By the way, I am incredibly indebted to Fenwah and his high speed creature switches described in http://www.bay12forums.com/smf/index.php?topic=62798.0 for this memory design, and from that, for everything I'm writing here.)

Hopefully you're noticing just how important signal management is. I said that we needed trips to execute our comparison loop, but like I said, that won't work for our comparison parameters. We need stable values-- open or close. That's where memory comes in. We just have to be careful not to write to memory at the same time that we're reading memory, or our comparisons won't make any sense. In a worst case scenario, a door might close on a goblin, or a hatch open up underneath him, and computation stops.

Practical concerns with goblin based computing

Let's take a break from logic and design for a minute. It's easy to forget that these aren't just bits moving around our fortress computer-- they're still invaders.

You have to pit them into your memory cell. If dwarves walk under or over our logic, they'll get interrupted. If a dwarf with a crossbow gets interrupted, he'll shoot your goblin. If you want to make changes to your logic designs, you have to kill any goblins occupying the space first.

To manage all of this, there are a few things you should do before pitting any goblins. All pits and all stairs to goblin access should be hatched over. Not locked hatches, of course, because that would break pathing. All spaces underneath channels should be walled off, or at least doored off. All objects (including stone) in the logic areas should be removed, so that dwarves don't path there. And you should have a couple of crossbows and a couple of bolts, because it can be a pain to find a melee route to a goblin in one of these circuits.

Cats pose a special problem. I've never seen them screw up goblin pathing, and I'm not sure they will, but they path into logic areas because these areas spawn vermin. Cats block doors when they close, and vermin corpses block doors too. Tightly closed hatches over your paths is a good start, but generally insufficient-- if a cat wants in, it will get in eventually.

There is one design decision that can solve this problem for you. Instead of doors, you can use hatches over ramps or staircases.

Hatches are really interesting because, depending on the surroundings, they can be built to allow path when closed (as when over a channel) or when open (as when over a ramp or staircase). And the big thing is that they never get stuck open.

One drawback that I've found with using hatches instead of doors is design convenience. It's hard to visualize a circuit when it spans multiple z-levels. The other drawback is the difficulty in designing doorless memory. It's possible, but inefficient.

Incrementing memory and percolating functions: the two-bit add

I want to show you a special kind of memory.

```  ###<#
##h#h#
##^#^##
#hd#dh#
##^#^##
#h#h##
#<###
```

This, of course, requires some explanation.

NE pressure plate corresponds to true. It is linked to both adjacent hatches. SW pressure plate corresponds to false. It is linked to both adjacent hatches. To set equal to true, open the west door. To set equal to false, trip the hatch to the NW of true. SE pressure plate sends a trip when state changes from true to false when triggered via 'toggle with carry.' It is linked to both doors of the next memory cell. To toggle with carry, open both doors. NW pressure plate isn't going to be used. Yet.

In other words, this is an unnecessarily complicated memory cell to use on its own, but it has nice functionality when put in a line of several, with the 'carry' plate of each linked to the doors of the next. We can still use it as normal memory (although it's a little slow for that purpose). It still forms a loop that follows our rules.

Imagine two of them, the first linked to the second (but not the second linked to the first!) When we toggle with carry to set memory a = 1, we don't do anything to memory b. But when we toggle with carry to set memory a = 0, we also send a toggle to memory b.

Imagine now that we have four bits of memory and an operation to add them. We have memory a1, memory a2, memory b1, memory b2.

```#######
#d^#d^#
r## ##c
#h #h #
#######
```

r is reset position, c is completion point; you can see that I left out infrastructure

The western doors and hatches are linked to a1, the eastern, to a2. The western plate carry-toggles b1, the eastern plate, b2.

Here's how it works in code:

```If a1 then b1=b1+1
If b1>1 then b1=0 and b2=b2+1
If b2=2 then b2=0
If a2 then b2=b2+1
If b2=2 then b2=0
```

We're adding bits! There's one problem, and I hope you noticed it. We can't write to memory twice at the same time! This percolation forms a write, and the second arm of our write operation isn't going to play pretty with it. We could do this:

```#################
#d^###########d^#
r##           ##c
#h ###########h #
#################
```

That would slow it down, but isn't guaranteed to work.

This is better:

```#################
#d^###########d^#
r##h         h##c
#h ###########h #
#################
```

In this case, the two central hatches we've created should be linked to the memory a1's carry-toggle, so that we institute an automatic 100 tick delay between writes. This is still not foolproof, but it's more foolproof.

Instituting Delay

The problem is that it's not safe to write to the next bit until the previous bit has had time to percolate. Since percolation uses a trip signal, we need to wait 100 ticks, plus any time for the goblin to move to his new position.

```#########
<h^h^h^h<
#########
```

This looks a lot like a memory cell. There's one extra pressure plate in the middle, though. It's not linked to any hatches in this circuit though.

When we send the two interior hatches a trip signal, they'll get a redundant open, then close 100 ticks later. Our goblin will run across the central plate, sending a trip.

Let's rebuild our adder. Remember, all operations are loops-- completion point can as easily serve as reset position for the next arm.

```#######
#d^#d^#
1##2##c
#h #h #
#######
```

1 is reset1, 2 is reset2

I haven't shown you infrastructure. We link reset2 to the interior hatches on our delay. But we can't link our delay trip to the begin hatch for reset2-- that's insufficient delay. Rather, we build a second delay circuit, linked to the first delay circuit-- that is, delay1 trips the interior hatches of delay2, and delay2 trips begin2 of our 2 bit adder. We now have >200 ticks delay before running the add on the second bit.

Hopefully, it's obvious how this can be expanded to add any number of bits. Hopefully, it's also obvious that percolating functions can be very slow. A 6-bit percolating add takes more than one in-game day to complete.

Subtraction is almost identical. The only difference is that we trigger the toggle with carry on a change of 0 to 1 rather than on a change of 1 to 0. In other words, rather than using our cell's SE pressure plate to toggle-with-carry the next bit, we use our cell's NW pressure plate. A slight redesign of our toggle-with-carry memory cell could allow toggle-with-carry(add), toggle-with-carry(subtract), and toggle.

Multiple word adds: the carry bit

Before we get any further, let's define a term. A word is a group of bits that we perform operations on as if it's a single datum. You're probably familiar with bytes-- a byte is an 8-bit long word. Words can be any length, but we're using 2-bit words because it lets us keep things simple, while demonstrating principles that can be expanded to words of any length.

Two bits don't give us very big numbers. We may need to use multiple words (of two bits each) to enable larger numbers. We want a carry bit.

A carry bit is an extra bit of memory that is set to 1 every time our last add (a2+b2) goes from 1 to 0, and is set to 0 every time our last add goes from 0 to 1. So we need both the NW and SE pressure plates on our last bit of adding memory.

To add two single numbers, each consisting of 3 2-bit words (add e,c,a to f,d,b) we need to:

```Add a and b, write carry
Add carry to c1, write carry
Add c and d, write carry
```

You can see that very large numbers are going to involve a large number of steps. We're much better off using larger words to begin with.

Multiple arm operations: two-bit compare

Let's build an arm that evaluates bits a1, a2, b1, and b2 and returns true if b>a.

```   ##############
##           ^##
### ########## # ##
#dh#     #### ### ##
r###     ##dh## ## #
# ######## ########c
## #dd  # #dd   ^# #
## #### ######## ##
## #hh# #hh ^# ##
## #### #### ##
##hd###hd# ##
### ####^##
##    ##
######
```

If you notice, there are 12 paths to run through from reset to completion. These paths are chosen such that one and only one is ever open. The goblin traces through two sets of evaluations. The first set of evaluations, on the left, correspond to b2 and a2 respectively; on the right, b1 and a1 respectively. That is, the most northwestern door corresponds to the state of b2, and the southeastern door corresponds to the state of a1. The northeast pressure plates returns true if b>a; the others are only necessary if we expand it.

Here's our goblins flowchart:

```If b2 and not a2 return true
If a2 and not b2 return false
If a2 = b2 then
If b1 and not a1 return true
Else return false
```

You can see that this > comparison actually contains all possible ordinal relationships of a and b: greater than, lesser than, and equal. We can put pressure plates anyplace we want to evaluate this. We can make those pressure plates do something or not do something with other circuits-- in other words, this is a complete 2-bit compare.

You might also suspect that an 8 bit compare of this design would be huge-- but not really. Look at the return from the southern and northern compare of bit 2. The design is as tall as it needs to be-- we only need to make it wider. With each bit we compare, we only have to continue our compare if a and b at a particular bit are equal. If one is larger or smaller than the other, we divert them into true or false returns.

The Pathing Stack

There's one problem in our comparison design, and you don't have to kick yourself if you didn't notice it. I haven't warned you about it yet.

I'm not entirely certain of how goblins path, but the seem to maintain a stack of locations where path was broken. What this means is that after a few runs of our comparison, there's a chance of a goblin behaving unpredictably. Consider what happens if he runs down the a2<b2 arm, but remembers that he wants to go down one of the a1=b1 arms. He might path backwards, tripping off an extra evaluation plate. I'm not sure if this will happen or not, but after that huge design, we don't want to risk it. Beyond that, it's easy for complicated operations to lead to multiple paths when considering possible retrograde motion through operations. We want to develop good design habits, so that we don't run into this problem.

We need a redesign. We could keep each arm separate, not feeding into the next, but by the end of an 8-bit comparison, we'd have 256 arms. That's not viable.

Infrastructure: Multiple Completion Points

Instead, we're going to give the goblin individual places to return to reset. We're going to give the goblin multiple completion points. All of these completion points will link into a single pathway to reset. We're going to use an extra z-level to make it clean. Before we do that, let's remind ourselves of the necessary components of a completion point:

```#######
#r#####
##d####
###^h<#
##h####
#o#####
#######
```
```o comes from operation, r leads to reset, < paths to map edge
```

I've walled it off to give us an idea of space requirements.

```z level 0
```
```     ##### #####
##dh<###dh<#
# ##### ####
# #   # #
# #   # #
# #   # #
# #   # #
# #   # #
##### ##### ####
#<h##  dd## dd<#
###rb####   ####
#<h##  hh## hh<#
##### ##### ####
# #   # #
# #   # #
# #   # #
# #   # #
# #   # #
# ##### ####
##hd<###hd<#
##### #####
```

r is reset position plate, b is begin hatch, < is upstairs

```z level 1
```
```   ###       ###
#>##      #>##
##h####   ##h####
###1h<#   ###2h<#
###d########d####
##     #  ##
###### ##d####
# ###3h<#
###       # ##h####
#X#       # #>##
########### ###
#>         ##>##
########### ##h####
# ###4h<#
###### ##d####
##     #  ##
###d########d####
###5h<#  ###6h<#
##h####  ##h####
#>##     #>##
###      ###
```

1-6 are completion point pressure plates, > is downstairs, X is up/down stairs that maps to map edge, < is upstairs that paths to map edge

So this is pretty large. You could shrink it, but it's better just to keep these things understandable. You chain it indefinitely to perform comparisons on words of any bit length. It is 21 tiles broad, and 10 tiles long for every bit evaluated.

Here's the problem. To make comparisons between even 4 words, we need 6 of these. That's not going to work. We need a way to be able to build this once, such that it can compare any of our words.

Continued at User:Vasiln/Goblin Logic 2