Funge-98

Unefunge and Trefunge: Funge in One and Three Dimensions

See how the Funge idea works in one dimension (Unefunge) and three (Trefunge), and how the instruction pointer, coordinates and turning instructions change.

On this page
  1. One idea, three sizes
  2. Unefunge: a program on a line
  3. Befunge in between
  4. Trefunge: adding a third axis
  5. What changes for the instruction pointer
  6. Why bother with the other dimensions

One idea, three sizes

Funge-98 is written so that the number of dimensions is a parameter. The two-dimensional member, Befunge, is the one most people know. The one-dimensional member is called Unefunge and the three-dimensional member Trefunge. Each follows the same recipe: a space of cells, a pointer with a position and a direction, a stack, and instructions that read the current cell. What changes is how many numbers it takes to say where you are and which way you are heading.

Unefunge: a program on a line

In Unefunge the whole space is a single line of cells. A position is one number, and a direction is one number too, so the pointer can move in only two ways: forward or backward. There is no up or down, which means no vertical arrows and no vertical conditional.

That sounds restrictive, and it is, but plenty of ideas survive. The pointer still starts at the left and moves right. A direction instruction can send it back the other way. The jump instruction still skips cells, the semicolon still marks a region to ignore, and the iterate instruction still repeats. Here is a minimal program:

55+.@

It pushes 5 and 5, adds them, prints 10 with a trailing space, and stops. A one-dimensional program looks like a very short Brainfuck program or a line of postfix arithmetic, and for good reason: it is a stack machine with a pointer moving along its own tape. The more interesting comparison is with the idea of tape versus grid as a memory model, since Unefunge is the point where the grid collapses into a tape.

The get and put instructions take a single coordinate in Unefunge, so the line serves as both the program and its variables. Wrapping is also simple: run off the right end and the pointer returns at the left, by the rules for the occupied region.

Befunge in between

For reference, Befunge sits at two dimensions, with a position written as two numbers and four basic directions. Get and put take two coordinates, with the row coordinate pushed last. Turning left or right has a clear meaning, because a plane has a left and a right of the direction of travel. This is the case people picture when they hear the word Funge, so it makes a good baseline for the other two.

Trefunge: adding a third axis

Trefunge adds a third coordinate, usually thought of as a layer or height. A position needs three numbers, and the space is a stack of two-dimensional pages. A direction is a vector of three components, so besides the four planar directions the pointer can move toward higher or lower layers.

New instructions handle the extra axis. One sends the pointer toward higher layers and another toward lower layers. A third is a conditional, like the horizontal and vertical ifs, which pops a value and picks between the two. The planar arrows still work as in Befunge and leave the layer unchanged. In a source file, the layers are typically separated by a form feed character, so each page of code is read as one plane and the pages are stacked in order.

Coordinates for reading and writing cells grow to three parts. A common description is that you push x, then y, then z, and the instruction pops them back in reverse order. Check how your interpreter documents this before relying on it, because getting the order wrong is an easy and confusing mistake.

What changes for the instruction pointer

The main difference is the size of the direction vector, which is also called a delta. In one dimension it is a single number, usually plus or minus one. In two dimensions it has two components, in three it has three. The pointer adds the delta to its position on every step, so a delta with a larger magnitude makes it skip cells. Seen this way, the jump instruction is simply a temporary larger delta, and the topic of delta vectors applies unchanged in every dimension.

Turning needs care. Left and right turns are well defined in a plane. In three dimensions, “left” depends on which plane you mean, so those turns act within the horizontal plane and leave the vertical component alone. The absolute-delta instruction handles the general case: it pops one number per dimension and sets the direction directly. That one instruction is how a program can steer in any direction at all.

Reflection also generalizes. Reversing a pointer means negating every component of the delta, and that works the same way whatever the dimension. That is why the unknown-instruction rule can be written once and apply to all three languages.

Why bother with the other dimensions

Unefunge is mostly a teaching and curiosity language, valuable because it shows what a Funge program looks like with the geometry stripped away. Trefunge is valuable for the opposite reason: it shows how quickly geometry gets hard. A three-dimensional program is difficult to draw, to trace by hand and to debug, because you can only see one layer at a time. Anyone who has worked with a trace visualizer for ordinary Befunge will see right away why a three-dimensional one would need slicing, rotation or color coding.

For readers interested in language design, the lesson is that a single abstraction, a pointer with a vector direction on a space of cells, stretches over very different shapes. The syntax barely changes; the practical difficulty changes a great deal.

The complete guide to funge-98

What Is Funge-98?
Read the guide

Keep exploring

Guides from other topics

All topics →