Grid Program Flow

How Grid-Based Program Flow Works

Learn how a pointer moving across a two-dimensional grid replaces the top-to-bottom reading of ordinary code, and how turns, loops and branches emerge from layout.

On this page
  1. From a list of lines to a map
  2. The pieces of a grid program
  3. A first look at a program that turns
  4. Branches without if statements
  5. What happens at the edges
  6. Why the layout becomes part of the logic
  7. Grid versus tape
  8. Getting comfortable

From a list of lines to a map

In most programming languages, source code is a sequence. The computer starts at the first statement, moves to the next, and only departs from that order when it meets a jump, a loop or a function call. The “where am I?” question is answered by a single number, such as a line or an instruction index, which usually just goes up by one.

Grid-based languages change that picture. The program is a rectangle of characters, and each character sits in a cell with a position. A pointer, often called the instruction pointer or program counter, sits in one cell at a time and also has a direction. After each step, it moves one cell in that direction. Instructions in the cells can change the direction, change what is stored, or both. Where the code is placed on the page therefore decides what happens next, and the reading order of the text no longer matters.

The pieces of a grid program

A typical grid language has four ideas working together.

  • The playfield. The grid of cells holding the program. Each cell holds a single character, and an empty cell is usually just a space that does nothing.
  • The pointer. It has a position and a direction. It usually starts in the top-left corner moving to the right.
  • Instructions. Single characters that act when the pointer lands on them. Some do arithmetic or output, some move values around, and some change the pointer’s direction.
  • Data storage. Often a stack of numbers, as in the Befunge language, though the details differ between languages.

The cycle is the same each time: read the cell under the pointer, carry out its instruction, then step one cell in the current direction. That is the grid version of the usual execution loop in any interpreter. The only twist is that “next” is computed from a position and a direction rather than from a counter that just increases.

A first look at a program that turns

Here is the smallest interesting grid program. It is two rows of two cells:

>v
^<

The pointer starts at the top-left cell moving right. The > instruction points it right, so it steps into the v, which turns it downward. It steps into the <, which turns it left. It then steps into the ^, which turns it upward, back to the >. Nothing in the program ever ends, because the pointer is trapped in a square of arrows.

Even though this does nothing useful, it shows the central trick. The repetition did not come from a while keyword. It came from the shape of the path. The principle is simple: a loop is a route that comes back to where it began.

Branches without if statements

Conditional behavior is handled by instructions that look at a value and then pick a direction. In Befunge-style languages, there are cells that pop a number from the stack and send the pointer one way if it is zero and the other way if it is not. A branch is then a fork in the road: the pointer arrives at the decision cell, and two different paths leave it. Each path can carry its own instructions, and the paths may later rejoin or end separately.

This is the grid equivalent of what other languages call conditional branching, with the difference that both outcomes are physically visible on the page as different corridors. There is no block structure, indentation or braces. If you can see the corridor, you can see where the pointer would go.

What happens at the edges

A grid has to end somewhere, and the language has to say what happens when the pointer walks off the boundary. Many grid languages answer by wrapping: leaving the right side makes the pointer reappear on the left side of the same row, and leaving the top reappears at the bottom. That makes the grid behave like the surface of a doughnut. The details, and what they mean for planning the layout, are covered in the article on wrapping edges. For now, the main point is that a pointer never really falls off the program; it keeps circulating.

Why the layout becomes part of the logic

In a line-based language you can reformat the code, adding spaces and blank lines, without changing what it does. In a grid language you usually cannot. Moving one character one cell to the left can change which instruction the pointer meets, or whether it meets it at all. This is both the charm and the cost of the approach.

The cost is readability. You cannot skim from top to bottom, and a neat-looking block of text can hide many crossing routes. This is a large part of why such programs belong with the two-dimensional languages and often feel like puzzles. It is also why careful code layout matters so much more than it does in an ordinary language.

The benefit is that the program’s structure is spatial. You can point at a loop with your finger. You can see which regions are never entered, a topic taken up in the discussion of dead code. You can draw the path with a pencil, which is the subject of flow diagrams, and you can add a second or third axis in languages that generalize the grid, as with the Trefunge dimensions idea.

Grid versus tape

It helps to compare this with other models. In a tape language such as Brainfuck, the program is still a straight list of instructions, and it is the data that lives on a one-dimensional tape. Here, the roles are blended: the program itself is a two-dimensional space that the pointer travels through, and some languages allow it to read and write that same space as data. Looking at tape versus grid as memory models makes the difference clearer, but the key difference for control flow is that a tape-language program still reads one instruction after another, while a grid program is walked.

Getting comfortable

The best way to build intuition is to follow a pointer by hand. Pick a small program, put a finger on the start cell, move it one cell at a time, and note the direction after each step. A pencil and a column for the stack are enough. Doing a few of these makes the pattern clear fast, and it is the same method used when tracing by hand a real program. After that, each of the related topics, such as the four directions, loops, unreachable cells and wrapping, is just a closer look at one part of the same moving-pointer idea.

Keep exploring

Guides from other topics

All topics →