ChemiCompiler

From Space Station 13 Wiki
Jump to navigation Jump to search
MechanicNew64.png This page is under construction.
The following information may be incomplete.
You can help by adding missing information or formatting.

"A complicated chemistry device, which uses a programming language derived from Brainfuck. It features 5 registers, 1024 bytes of RAM and 10 reagent reservoirs - to add beakers, click on the r[number] slots. It also has a pill generator, a vial generator and an ejection port. "

Piff paff. Complicated? I think not. Scientists worth their salt can figure this out. Eventually.

Signals

During normal operation, the chemicompiler emits a number of audible cues to provide you feedback. These are as follows:

  • ChemiCompiler CCS1000 beeps quietly 2 times.

Beginning of a program.

  • ChemiCompiler CCS1000 beeps loudly once.

An operation has failed, probably due to a missing beaker in either sx or tx.

  • ChemiCompiler CCS1000 emits a slight humming sound.

Transfer step in a program

  • ChemiCompiler CCS1000 clicks.

Heating step in a program, once each for the beginning and end.

  • ChemiCompiler CCS1000 beeps quietly once.

The program has finished running and the machine is idle.


The sprite will animate while the machine is running, and it will also provide the normal chemical reaction messages if they occur.

Guide to Making Chemcompiler Programs/Reactions

The Chemcompiler seems arcane, and almost useless at first glance. But imagine a cocktail like this:

25 Fluorosulfuric acid
24 Phlogiston
24 Dark Matter
12 Smoke Powder
12 Fluorosurfactant
3 Plasma

It's a bomb, it's a face-eater, it's a fireball. It's everything, and it will kill you dead in seconds with a drop - I know, I've tested it on myself after testing it on monkeys. I dunno, or maybe it sucks, but I like it :<

Using the chemcompiler, I will show you how to systematically create the beginnings of this mixture (or blow you to hell, if you didn't load the beakers right), and hopefully give you some idea what the hell it's about. If you use this guide, a fair payment would be giving me all your programs/plans so that I can murder myself more effectively.

Initial steps and planning

In order to make a coherent ChemCompiler program, you first need to have a plan for every step of your reaction. A lot can go wrong. But if you follow things through systematically, you might be ok.

'ΤΗΕ Ρ⌊ΔΝ ¦ς Α§ ΙΜΡΩℜΘΑΝΘ Ας ⊥Η∃ ϖℜœℑ®αΜΜìñϑ∴', though neither is as important as wasting time on the internet. Do not neglect your plan. We will actually code alongside it - it will be our comments and our test data every step of the way.

Let's do something simple first: Sulfuric acid into Fluorosulphuric Acid. It's sulfuric acid, fluorine, hydrogen, and potassium in equal quantities. It also needs to be heated up to 374 degrees. Sulfuric needs sulfur, oxygen, and hydrogen. Obviously we need to make that first. Also, when working with the chemcompiler, you need to respect the amount available to you in each beaker as well as (and this is my approach, not necessarily the best one) the amount of room left in the final output beaker. So we document all of that to ensure a clean reaction and help with testing later.

I start it out looking like like this:

Sulfur 50/50
Oxygen 50/50
Hydrogen 50/50 (2x)
Fluorine 50/50
Potassium 50/50
Mixdown 0/100

Note that I marked what is used twice in the reaction - you should do this so that you know, later, which ones are best to double up a beaker with, because you only have 10 slots, and for complicated reaction chains you run dry fast.

Let's say we want that final mixdown beaker to be 3/4s full of fluorosulphuric acid in the end. We know that we need four components to make it, so we'll need 1/4 of it full of sulfuric. But sulfuric has 3 components! We'd end up needed 12.5 of sulfur, oxygen, and hydrogen. No good. What we can do instead is make more than what we need, and put it into a buffer mix. That's not a great solution for more complex reactions, but it's worth remembering as a fix, because residual chemicals suck. The buffer can be emptied at any time in the ChemCompiler using a few simple operations.

Sulfuric

Our new setup looks like this

Sulfur 50/50
Oxygen 50/50
Hydrogen 50/50 (2x)
Fluorine 50/50
Potassium 50/50
Buffer 0/50
Mixdown 0/100

So now we know we need:

13 sulfur
13 oxygen
13 hydrogen
Into buffer
works out to 26, so 25 into mixdown

We want to keep track of these changes, because running out of something is potentially dangerous

Sulfur 37/50
Oxygen 37/50
Hydrogen 37/50 (2x)
Fluorine 50/50
Potassium 50/50
Buffer 1/50 (sulfuric acid)
Mixdown 25/100 (sulfuric acid)

Into fluorosulfuric

Now we move on to the final mix. We already have the sulfuric acid ready, so we need

25 fluorine
25 hydrogen
25 potassium
 
Sulfur 37/50
Oxygen 37/50
Hydrogen 12/50 (2x)
Fluorine 25/50
Potassium 25/50
Buffer 1/50 (sulfuric acid)
Mixdown 100/100 (25 sulfuric acid, 25 fluorine, 25 hydrogen, 25 potassium)

Now we need to document the heating needed to change the precursors into our final form.

Heat Mixdown to 374

Sulfur 37/50
Oxygen 37/50
Hydrogen 12/50 (2x)
Fluorine 25/50
Potassium 25/50
Buffer 1/50 (sulfuric acid)
Mixdown 100/100 (75 Fluorosulphuric acid!)

Success! It may seem overly redundant to lay it out like this, but we can use it to make our ChemFuck program quickly and easily now, and the real fun begins.

Introduction to ChemFuck

Everything in Brainfuck/the ChemCompiler is about manipulating the Pointer. Think about the Pointer like a mouse that can go left or right. It's always hovering over a number (it begins at the very first one available), and those numbers have their own locations in memory (references) So initially it looks like this

  v
00x000 01x000 02x000 03x000 ... FFx000

The first two numbers are the Reference. The last three, after the x, are the Value. We can do two things with the pointer - we can shift the Reference left (<) or right (>). We can add 1 to the value (+) or subtract (-).

Already we know how to do something useful. Say we wanted the numbers 1 through 10 stored in memory. This would be the program to write it

+>++>+++>++++>+++++>++++++>+++++++>++++++++>+++++++++>++++++++++

So stepping through, it first adds 1 to the first (always 00) reference

+
  v
00x001 01x000 02x000 03x000 04x000 05x000 06x000 07x000 08x000 09x000

Then it moves the pointer over 1 (>)

+>
  ------>v
00x001 01x000 02x000 03x000 04x000 05x000 06x000 07x000 08x000 09x000

Then it adds 1 to that reference twice

+>++
         v
00x001 01x002 02x000 03x000 04x000 05x000 06x000 07x000 08x000 09x000

And so forth, ending on reference 09 incrementing its value to 10

+>++>+++>++++>+++++>++++++>+++++++>++++++++>+++++++++>++++++++++
                                                                 v
00x001 01x002 02x003 03x004 04x005 05x006 06x007 07x008 08x009 09x010

Because there is no multiplication or direct entry of numbers in Brainfuck, it's helpful to copy/paste +/- signs in known quantities if you need to reach larger numbers. And yes, chemfuck programs really are just long strings of symbols.

Here's all of them at once to confuse you!

Commands

Basic pointer manipulation and arithmetic

  • > Increment the reference position
  • < Decrement the reference position
  • + Increment the value of the reference under the pointer
  • - Decrement the value of the reference under the pointer

While loops

  • [ Start a While loop (returns to this spot when it hits ], and goes off to ] if the reference value under the pointer at that time is 0
  • ] Same as above, but exactly backwards. Yes, backwards. As in the program checks if the current value is 0, reverses itself until it hits a [ if not, and then it returns and does its check again. What. (if you think about it carefully, this doesn't infinite-loop either type of while loop, so why not?)

Register operations:

  • { Set the Source register to the current reference (number) under the pointer. The Source register (sx on the chemcompiler screen) is typically whatever beaker you're taking chemicals from next.
  • } Set the Source register to the current reference value
  • ( Same as {, but for the Target register. The Target register (tx) you might have guessed is where a chemical will go if it's moved during the current step of the program, for instance.
  • ) Same as }, but for the Target register
  • ^ Same as ( or {, but for the Amount register. Amount (ax) is used for both the amount of chemicals to be moved, and Temperature values.
  • ' Same as } or ), but for Amount.

You get the idea, hopefully. There's two for each of these. If the chemcompiler throws out a string of loud beeps the first time you load a program into it, you've probably gotten these backwards.

Other operations:

  • $ Heat or cool reagent in sx to ((273 - tx) + ax) Kelvin.
  • @ Transfer ax units of reagent from reservoir sx to target tx.
  • ~ "Compile" the code, so it cannot be retrieved again via the load button.

Actual Brogramming

So now that I've thoroughly confused you, we can move on to making our first reaction in the chemcompiler. Isn't that exciting? Are you bored yet? Fuck you. This took a long time to write and test, you better stick with me you brat.

Sulfuric

We'll start with the setup

1 Sulfur 50/50
2 Oxygen 50/50
3 Hydrogen 50/50 (2x)
4 Fluorine 50/50
5 Potassium 50/50
9 Buffer 0/50
10 Mixdown 0/100

Notice the numbers before each. These are the registers we're using. We could have made them anything from 1-10, but at the very least I like to make the final mix be register 10 for consistency. They're the numbered buttons in the chemcompiler menu. You load the beakers into the compiler by putting one into your hand and clicking the corresponding button - the beaker should disappear and the button should light up. Click the button again to retrieve into an empty hand.

You should start by loading this mix into the compiler. Every single one, yes. Don't leave any out.

To begin with, it's really useful to load a bunch of values into the program that represent our registers, and just common numbers that we'll use constantly, so let's do that.

+>++>+++>++++>+++++>++++++>+++++++>++++++++>+++++++++>++++++++++>+++++++++++++>+++++++++++++++++++++++++

That last two is 13 and 25. They're there so that we can handle the sulfuric step without too much extra movement. You want to conserve movement as much as possible, because you have a -lot- of memory available.

We'll take the section of our plan and add to it directly. In your plan you can just edit it rather than make a giant wiki page to show your work like I did.

13 sulfur(R1)
13 oxygen(R2)
13 hydrogen(R3)
Into buffer(R9)
works out to 26, so 25 into mixdown(R10)

Right now (after the values we loaded) we're at reference 12. We can visualize it as something like this

+>++>+++>++++>+++++>++++++>+++++++>++++++++>+++++++++>++++++++++>+++++++++++++>+++++++++++++++++++++++++

Memory and Pointer:
                                                                               v
00x001 01x002 02x003 03x004 04x005 05x006 06x007 07x008 08x009 09x010 10x013 11x025

There's three things we want to do now. We want to set tx to 9, or Buffer. We want to set sx to 1, or Sulfur. And we want to set ax to 13 - that's how much sulfur we want. We do that by finding either a reference or a value (we'll be using values to avoid confusing you, but they're both numbers, see?)

<<<
Memory and Pointer:
                                                          v
00x001 01x002 02x003 03x004 04x005 05x006 06x007 07x008 08x009 09x010 10x013 11x025

And set tx

) (Registers: tx = 9)

Then we move back over to reference 10, which has the value 13 we need for ax.

>>' (Registers: ax = 13)
Memory and Pointer:
                                                                        v
00x001 01x002 02x003 03x004 04x005 05x006 06x007 07x008 08x009 09x010 10x013 11x025

I like to annotate the plan directly with these short sections of code as they fall out naturally.

Oh yeah. If you're confused about register 9 being '08', it's because I didn't explain you didn't notice that everything for references starts at 00. So one is 00, two is 01, and so on. Pay more attention!


So now we add in the modification to the Source register. It needs to be 1. I'm going to go ahead and throw it down like I was actually doing this for a living and annotate our plan, but the bold step is what we've just done.

+>++>+++>++++>+++++>++++++>+++++++>++++++++>+++++++++>++++++++++>+++++++++++++>+++++++++++++++++++++++++

13 sulfur <<<)>>'<<<<<<<<<<}      (Registers: sx 1, tx 9, ax 13)
13 oxygen
13 hydrogen
Into buffer
works out to 26, so 25 into mixdown
Memory and Pointer:
  v
00x001 01x002 02x003 03x004 04x005 05x006 06x007 07x008 08x009 09x010 10x013 11x025

So now we add the @ at the end to move the sulfur

@

and we can finally do something! We move 13 units of sulfur to register 9, or the buffer beaker you put into place. You did put it into place, right? Compositing all of the code so far together, you get

+>++>+++>++++>+++++>++++++>+++++++>++++++++>+++++++++>++++++++++>+++++++++++++>+++++++++++++++++++++++++<<<}>>'<<<<<<<<<<}@

You can drop this into the compiler and test it out if you like. Hit Save, click 1 (in 1-6), and click 1 again. The compiler should beep a few times, and the sulfur should be moved. It pays off long-run to test these steps as you go, since things may not mix exactly as you expect, you may make typos, you can count wrong, etc. Science! Face melting!

By now, it should be pretty obvious what to do next, but I'll walk through it just in case.

+>++>+++>++++>+++++>++++++>+++++++>++++++++>+++++++++>++++++++++>+++++++++++++>+++++++++++++++++++++++++

13 sulfur <<<)>>'<<<<<<<<<<}@      (Registers: sx = 1, tx = 9, ax = 13, and move)
13 oxygen >}@                  (Registers: sx = 2, and move)
13 hydrogen >}@                (Registers: sx = 3, and move)
Into buffer
Memory and Pointer:
                v
00x001 01x002 02x003 03x004 04x005 05x006 06x007 07x008 08x009 09x010 10x013 11x025
works out to 26, so 25 into mixdown
>>>>>>} (Registers: sx = 9)
Memory and Pointer:
                                                          v
00x001 01x002 02x003 03x004 04x005 05x006 06x007 07x008 08x009 09x010 10x013 11x025
>) (Registers: tx = 10)
Memory and Pointer:
                                                                 v
00x001 01x002 02x003 03x004 04x005 05x006 06x007 07x008 08x009 09x010 10x013 11x025
>>'@ (Registers: ax = 25)
Memory and Pointer:
                                                                               v
00x001 01x002 02x003 03x004 04x005 05x006 06x007 07x008 08x009 09x010 10x013 11x025

And just like that:

+>++>+++>++++>+++++>++++++>+++++++>++++++++>+++++++++>++++++++++>+++++++++++++>+++++++++++++++++++++++++<<<)>>'<<<<<<<<<<}@>}@>}@>>>>>>}>)>>'@

You now have a program to mix sulfuric acid. Only with this setup, granted (sulfur in Register 1, oxygen in Register 2, hydrogen in Register 3, and an empty, empty beaker in 9 and 10 each) but it'll work. Hopefully. I didn't test it, by the way.

Into fluorosulphuric precursor

Taking the rest of the plan, we do not need to shift tx or ax except at the very end. It's now a breeze to transfer the rest of the components for fluorosulphuric acid and cook the mix.

+>++>+++>++++>+++++>++++++>+++++++>++++++++>+++++++++>++++++++++>+++++++++++++>+++++++++++++++++++++++++<<<)>>'<<<<<<<<<<}@>}@>}@>>>>>>}>)>>'@

Registers: sx = 9, tx = 10, ax = 25

25 potassium <<<<<<<}@ (Register(s): sx 5)
Memory and Pointer:
                              v
00x001 01x002 02x003 03x004 04x005 05x006 06x007 07x008 08x009 09x010 10x013 11x025
25 fluorine  <}@      (sx 4)
Memory and Pointer:
                       v
00x001 01x002 02x003 03x004 04x005 05x006 06x007 07x008 08x009 09x010 10x013 11x025
25 hydrogen  <}@      (sx 3)
Memory and Pointer:
                v
00x001 01x002 02x003 03x004 04x005 05x006 06x007 07x008 08x009 09x010 10x013 11x025

Combined together:

+>++>+++>++++>+++++>++++++>+++++++>++++++++>+++++++++>++++++++++>+++++++++++++>+++++++++++++++++++++++++<<<)>>'<<<<<<<<<<}@>}@>}@>>>>>>}>)>>'@<<<<<<<}@<}@<}@
Register: sx = 3, tx = 10, ax = 25


Into fluorosulphuric (Heating explained)

So after much register shuffling, now comes heating.


Unlike the rest of the values in the wiki, it's based on Celsius. You can use the Googles to figure out how much you need to heat the mixture.


It also, counterintuitively, heats the Source register sx. So that should point at the beaker we want to heat. 10 is the beaker that we want to heat. Definitely not 3.


It also subtracts tx from 273, so that you can reach negative values if necessary. We'll just set tx to zero.


Finally it adds ax.


So first, we're setting sx to 10 (the mixdown), setting tx to 0 (we already have this, we just need to go to the next uninitialized reference) and setting ax to 190! Then we use the heat operation, $

>>>>>>>} (Register: sx = 10)
Memory and Pointer:
                                                                 v
00x001 01x002 02x003 03x004 04x005 05x006 06x007 07x008 08x009 09x010 10x013 11x025

>>>) (Register: tx = 0)
Memory and Pointer:
                                                                                      v
00x001 01x002 02x003 03x004 04x005 05x006 06x007 07x008 08x009 09x010 10x013 11x025 12x000

>++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++'
(Register: ax = 190)

Memory and Pointer:
                                                                                              v
00x001 01x002 02x003 03x004 04x005 05x006 06x007 07x008 08x009 09x010 10x013 11x025 12x000 13x101

$ (Heat!)
sx = 10, tx = 0, ax = 190

Copy/pasting all of that together, we get our glorious finished program, giving 100 fluorosulphuric acid from raw reagents, with only a modest amount of clicking.

+>++>+++>++++>+++++>++++++>+++++++>++++++++>+++++++++>++++++++++>+++++++++++++>+++++++++++++++++++++++++<<<)>>'<<<<<<<<<<}@>}@>}@>>>>>>}>)>>'@<<<<<<<}@<}@<}@>>>>>>>}>>>)>++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++'$

Homework/Addendum

You can compile a program using the ~ instruction. Put it at the end, and load it in. This prevents anyone from tinkering with it behind your back.


For fun reference purposes, the final memory footprint of our program looks like this probably:

00x001 01x002 02x003 03x004 04x005 05x006 06x007 07x008 08x009 09x010 10x013 11x025 12x000 13x101


Setting tx to 11, 12, and 13 makes pills, vials, and disposes of reagents accordingly, when using the transfer (@) operation. If you're still not comfortable with the idea of making a plan like this of your own, try making an addition to the program to get rid of the lone remnant sulfuric acid in register 9, or make the compiler spit out acid pills, etc.


The while operators can create looping patterns in your program to do repetitive things without so much typing. But it's brainfuck. Most programs are like two lines long anyway. It's something to keep in the back of your mind while making your own programs/plans.


After you're done making fluorosulphuric, you have 3 (or 4, if you can keep from using the buffer) beakers to use for Science. Adding additional reactions, considering what you already have available, should be an obvious improvement to the program. The register layout for the first mixture I mentioned, before I got lazy decided that making the two acids was enough to teach everything you could need was this:

1 - Stabilizer 2x
2 - Plasma 2x
3 - Radium/Carbon 50/50
4 - Potassium/Sugar 50/50
5 - Sulfur 2x
6 - Hydrogen 3x
7 - Oxygen 2x
8 - Fluorine
9 - Phosphorus 2x
10 - mix

But you can make your own recipes. Remember that the plan is key! Fancy Chemistry is not all bad.