CraftyFunge is a 3-dimensional esoteric programming language written by placing Minecraft blocks. It requires 1.19 Java Edition. Programs can be run directly in Minecraft or with the external interpreter. The external interpreter accepts programs exported from structure blocks. CraftyFunge is executable in vanilla Minecraft using the provided world with an embedded data pack.
Much like other fungeoids, the Instruction Pointer (IP) has no fixed direction, and can be redirected in any of 6 possible ways. Each block is treated as one instruction. There is no wraparound, and when executed in Minecraft the IP will continue on until it reaches an unloaded chunk. When executed with the external interpreter it will raise an exception.
For storage, CraftyFunge uses both a stack and variables. Commands read and write to the stack, but for convenience there are commands to read and write to variables. Additionally, as a way of storing data or modifying its own code, CraftyFunge can get and set blocks.
When run in Minecraft, the stack has a maximum length of 128, and there are 128 possible variables from indices 0-127. Further pushes to the stack will overwrite earlier values, and attempting to access indices outside of the allowed range will truncate to the nearest value in range. Each cell is a 32-bit integer with a minimum value of -2,147,483,648 and a maximum value of 2,147,483,647. Attempting to go past these limits will result in wraparound. These limits are removed for the external interpreter.
When programming in Minecraft, beware of redstone interactions. Observers can activate pistons placed next to them, and the button used to activate the starting command block can do so as well. If this happens when importing a structure, keep reloading the structure. Eventually the observers should stop updating and the program will work.
All coordinates are relative to the starting command block, although it is recommended to place the starting block at (0, 0, 0) so the coordinates line up.
Numbers can be pushed to the stack using concrete, terracotta, wool, stained glass, or shulker boxes. The value depends on the color and block type. Colors are as follows:
Color | Digit |
---|---|
Red | 1 |
Orange | 2 |
Yellow | 3 |
Lime | 4 |
Green | 5 |
Light Blue | 6 |
Cyan | 7 |
Blue | 8 |
Purple | 9 |
Multipliers are as follows:
Block | Multiplier |
---|---|
Concrete | 1 |
Terracotta | 10 |
Wool | 100 |
Stained Glass | 1,000 |
Shulker Box | 1,000,000 |
The value pushed is the product of the digit and the multiplier. For example, green concrete would push 5, and cyan wool would push 700.
To push 0 to the stack, use white concrete.
Get block, set block, and input text literal assign a numeric value to each block. Concrete/terracotta/wool/stained glass/shulker box blocks that can be used to push numbers all have the same block values as their literal forms. An exception to this is air, which has a block value of 0 instead of white concrete, which has the special value of -2,147,483,648. Other blocks are used to fill in the gaps.
For a full list of block values, see block_values.md
While in default mode, the IP will execute instructions according to the instruction table. The IP starts in default mode.
While in tunneling mode, the IP will continue in the same direction until it reaches another deepslate block, ignoring any other instructions.
While in numeric literal input mode, the IP will read a number digit-by-digit and push that to the stack. White concrete counts as 0, and colored blocks of concrete/terracotta/wool/stained glass/shulker box (it doesn't matter the block type) correspond to the other digits 1-9. A coal block will negate the result, and additional coal blocks have no effect. The IP will ignore all other instructions except for direction changes from pistons and will exit when it reaches another glass block. If the IP doesn't read any valid blocks while in this mode, it will push 0.
While in text literal input mode, the IP will push the block value of each block it encounters to the stack until it reaches another tinted glass block. This is analogous to Befunge's string mode. One limitation is that tinted glass blocks (having block value INT32_MAX = 2,147,483,647) cannot be read through text literal input. They can still be read through get block or push next block value.
Input is written in the book and quill Input and is placed in the chest marked Input before running a program. Programs are limited to one page of input.
CraftyFunge supports pre-populating the stack. For the external interpreter, this is achieved with the command-line option -s
. In Minecraft, edit the book in the "Stack Pre-Population" chest. Values are read into the stack from left to right, so the rightmost value is the top of the stack.
The default execution speed in Minecraft is one instruction per 3 ticks, or 0.15 seconds. The scoreboard player and objective $ip delay
controls this if you want to speed up or slow down the execution rate. To go even faster than one instruction per tick I recommend the mod Carpet and the command /tick rate
. Be aware that high speeds cause the IP's position to start to smear as it can't keep up with the teleportations, however this is purely cosmetic.
- Write a program by placing blocks
- Activate a command block containing the command
craftyfunge:start
. The IP will start from that block and execute the program.- To run a program stepwise for debugging, replace the command with
craftyfunge:start_step
. To run a step, run the commandcraftyfunge:run_step
- To run a program stepwise for debugging, replace the command with
craftyfunge [-h] [--version] [-w] [-d] [-l [DEBUGFILE]] [-s STACK] [-i INFILE] [-o OUTFILE] FILE
Runs the program FILE
, where FILE
is an nbt file exported from a structure block.
Flag | Description |
---|---|
-h , --help |
Print a help message. |
--version |
Display the version. |
-w |
Run a file from the structure block export location <WORLD>/generated/craftyfunge/structures/ , where <WORLD> is the world save location loaded from world.cfg . Fails if no world location has been specified. |
-d |
Run the program in debug mode, printing the position, block, and stack at each step. |
-l [DEBUGFILE] |
Log the debug output separately. Defaults to debugout.txt . Has no effect if -d is not called. |
-s STACK |
Pre-populate the stack with the values in STACK , which must be formatted as a comma-separated list of integers surrounded by square brackets with no spaces. Ex. [1,2,3,4,5] |
-i INFILE |
Take input from INFILE instead of stdin. |
-o OUTFILE |
Send output to OUTFILE instead of stdout. |
You can export a program from Minecraft using a structure block and save it to craftyfunge:<program>
. This will generate an NBT file at <WORLD>/generated/craftyfunge/structures/<program>.nbt
, where <WORLD>
is the world save folder. To execute, you can either specify the full path to the program or you can configure your world save location in world.cfg
and use the -w
option.
While it is entirely possible to program in CraftyFunge without the use of mods, they do bring quality of life improvements. I recommend the following:
You need the following dependencies:
After that, go to src/craftyfunge.spec
and edit the variable startPath
to the absolute path of wherever src
is on your computer.
Then, run build.bat
and let PyInstaller do its thing.
Made by Eli Fox
String Parser library datapack by Suso, with help from McTsts and Gibbsly