The Machine
It’s pretty common knowledge that my primary occupation is software engineer. This means I occasionally dream of the lost days of Ada Lovelace and Charles Babbage, and their mathematical machines. While I was working on the Riverwatch dungeon (more on that next week,) I had the idea that the head cultist was building divinely inspired machines of the same nature. The knowledge of Aeto-Krah, plus a compulsion to create intricate items and improving manual dexterity results in something that lies between the Marble Machine X and an analog computer.
Unfortunately, unable to stop at "it’s a machine, it’s weird," I’ve spent some time making a simulator for it, which means others can write their own programs for it, and produce their own weirdness.
The simulator is here, and the rest of this post is documentation, which may be too high level for people not versed in programming, but I’d be here forever if I wanted to explain everything. You can likely do some research on some other assembly-programming games, TIS-100 is a great one to start with.
Components
The big clockface is your working register, and the 8 smaller clockfaces are your memory registers. Before beginning your calculation, you can pre-set the memory registers to inject input into your program.
Memory registers are numbered 0-7 (because of binary) so be sure to keep that in mind if you’re confused by the result of your code.
GM Mode
When you’re creating, you’ll likely want to stay in GM Mode, as that allows you to use string shorthand for operations rather than coding in binary.
Instructions consist of 2 parts, an operation and a data. Operations are 1 of the 16 actions the machine can preform, and data is a number between 0 and 1023, which may or may not be used.
Operations
There are 16 operations that the machine can preform:
00 |
01 |
10 |
11 |
|
00 |
AND |
AND* |
ADD |
ADD* |
01 |
OR |
OR* |
SUB |
SUB* |
10 |
NOT |
RST |
SAVE |
LOAD |
11 |
JEQ- |
JEQ+ |
JNE- |
JNE+ |
ADD & ADD*
These are pretty straightforward. ADD increments working memory by whatever number you gave it, while ADD* will add the value in whatever memory register you gave it.
For example, calling ADD 5
will increment the working register by 5, while calling ADD* 5
will increment the working register equal to whatever is in the 5th memory register.
AND & AND*
Similar to ADD, but instead of incrementing, it does bitwise add.
OR & OR*
Identical to AND but bitwise or.
SUB & SUB*
The subtraction equivalent to ADD.
NOT
This command ignores whatever data was put in, instead just does a bitwise not on the working value.
RST
This command also takes no data, but simply resets the working register to 0. This can be useful as a first command, as the working register is not changeable by the user. If there are programs left with the machine, a card with RST then SAVE 0-7 will likely be in them, as it’s a quick way to reset everything to zero.
SAVE & LOAD
Saves the working value to the indicated memory register, and vice versa
JEQ+, JEQ-, JNE+, JNE-
These 4 commands are described together because they are by far the most complicated… kinda.
JEQ commands move if the working value is 0, while JNE moves if the working value is anything but 0.
The plus or minus indicates if you want to skip further down the program (+) or back up the program (-).
The one caveat to these is thus: The last thing the computer does is move the program forward 1. This means that if you want to rerun the last command, you want to jump -2, not -1. Conversely, if you want to jump forward 5, you need to actually jump +4.
Save To Plate
Once you’re happy with your program, you can click the "save to plate" button to produce a text representation of just the holes (similar to the card laid out next to your code on run.) This can be given to the players as a handout, if you want to give them access to the machine.
Some Example Programs
These example programs are in GM mode, but they can be quickly converted to player mode by using the "save to plate" command.
Adds all 8 memory values together into the working register
RST
ADD* 0
ADD* 1
ADD* 2
ADD* 3
ADD* 4
ADD* 5
ADD* 6
ADD* 7
Calculate the next prime number after whatever is in memory register 0 and saves it to working memory and register 0. You can run this program over and over to get progressively larger prime numbers.
LOAD 0 // get last prime
ADD 2
SAVE 0 // save prime candidate
AND 0
ADD 3
SAVE 2 // new divisor
SAVE 6
LOAD 0
SUB* 2
JNE+ 2
LOAD 0 // load to working
JNE+ 1023
SAVE 1
SUB 1
SAVE 5
LOAD 6
SUB 1
SAVE 6
JEQ+ 6 // 5 >= 6
LOAD 5
JEQ+ 1 // 5 < 6
JNE- 9 // Reduce again
LOAD 2
ADD 1
JNE- 20 // Jump to new divisor
LOAD 5
JEQ+ 3 // 5 == 6
LOAD 2
SAVE 6
LOAD 5
JNE- 19 // loop
LOAD 0
JNE- 32 // divisible
Multiply memory 0 by memory 1
RST
LOAD 0
JEQ+ 1023 // 0 * X = 0
LOAD 1
JEQ+ 1023 // X * 0 = 0
SAVE 2
RST
SAVE 3
LOAD 3
ADD* 0
SAVE 3
LOAD 2
SUB 1
SAVE 2
JNE- 7
LOAD 3