Space Station 13 is a top-down tile based action role-playing multiplayer video game running on the freeware BYOND game engine, originally released in 2003
– Wikipedia
My brother, Eli plays this game, Space Station 13. Well, actually, he plays a fork of it that runs a server called Goonstation. The point is that you are doled out a role on the eponymous space station, and it is up to you to play that role, to the best of your ability, while faced with all kinds of antics and shenanigans.
Space Station 13 tracks all kinds of crazy levels of detail, Dwarf Fortress style, and Goonstation adds even more complex pseudo-realism on top of that.
Eli has shown me different aspects of play on Goonstation before, and has even asked for my help once or twice in the past to understand how the door-hacking system works, or how the networking between different computers on the station is done (also for hacking, Eli is a bit of a mischief maker no matter what role he plays).
But something he showed me a couple days ago really caught my attention. Goonstation has a really complex chemistry system. The formulas are somewhat realistic and thought out, and the number of compounds you can create is pretty insane. Being good at chemistry in Goonstation is a pretty big deal, since it means that you can create poisons, medicines, bombs, holy water, and even drugs like “triple meth” (I didn’t ask).
Being somewhat realistic, the formulations of these compounds get complex and tedious pretty quick, what with the mixing, isolating, heating, cooling, measuring, and keeping track of products, by products, and multitudes of beakers, all while crazed doctors try to trap you in whirring treadmill deathraps, hacked up robo-security tries to hunt you down, and guys dressed in clown suits keep pushing you over slippery tiles to make you fall down.
So, the devs of Goonstation created a machine called the ChemiCompiler. Basically just an automated pipette, beaker heater, and pill dispenser, it can take up to 10 beakers at a time and be programmed to do very complex chemical tasks.
Yes, you heard right! Programmed. But, and here’s the rub: you have to program the ChemiCompiler in a special adaptation of Brainfuck called “ChemFuck”. I’m convinced this is to keep the chemistry system balanced given how strong it is to be good at chemistry.
For those not familiar, brainfuck is a dumb, dumb, dumb programming language. It treats all memory as an infinite row of “cells”. Each cell starts at zero and may only store integers. A brainfuck machine also keeps track of a “pointer” which points to one of the cells at a time, and is also the default target for most brainfuck commands.
Here are all of the canonical brainfuck commands:
>
- move the pointer one cell ‘forward’ in memory
<
- move the pointer one cell ‘backward’ in memory
+
- increment the value of the cell under the pointer
-
- decrement the value of the cell under the pointer
[
- loop start, if the value under the pointer is zero, move past the matching loop end
]
- loop end, if the value under the pointer is not zero, move back to the loop start
,
- in typical brainfuck, this reads in one cell of input and stores it at the pointer
.
- print out the value in the current cell as an ASCII character
So, in order to print out an ASCII ‘A’, one would need to execute something like ++++++[>++++++++++<-]>+++++.
This program stores 6
into cell 0, then enters a while loop where we increment cell 1 ten times, move back to cell 0, and decrement it. This gets us up to 60 in cell 1, so we increment cell 1 5 more times and print it.
ChemFuck adds 3 additional registers, sx
, tx
, ax
, or source
, target
, and amount
respectively, and some specialized commands that read from/write to those registers, and perform side effects in the specialized hardware:
}
- move the value of the cell under the pointer to sx
{
- move the value of sx
into the cell under the pointer
)
- move the value of the cell under the pointer to tx
(
- move the value of tx
into the cell under the pointer
'
- move the value of the cell under the pointer to ax
^
- move the value of ax
into the cell under the pointer
@
- transfer ax
units of reagent from beaker index sx
to beaker index tx
$
- heat/cool beaker index sx
to ((273 - tx
) + ax
) degrees Kelvin
,
- Chemfuck re-purposes this command to measure the volume stored in beaker index sx
and store the value in ax
#
- isolate ax
units of reagent index under the pointer from beaker index sx
to beaker index tx
, this is particular to the way the game stores the contents of beakers. If a beaker has both water and mercury in it, those are stored as two separate amounts which must be accessed by index for isolating
Now, my brother is not a programmer, and even if he was, nobody wants to program in ChemFuck. So, I’ve devised a small project that will let my brother list out the steps he wants his process to take, and this web interface will spit out semi-optimized chemfuck for him to copy-paste into the game.
I’ve already built a little chemfuck simulator so I don’t have to boot up the game to test the outputs:
This is some of the most fun programming I’ve had in a long time!