Brainfuck the Drinking Game

Introduction

Brainfuck is an esoteric programming language originally invented as a Turing-complete language suitable for making really small compilers. There are only eight instructions in the language, and two of these are not strictly necessary. The rest map nicely onto a die.

Let me give a quick overview of the Brainfuck virtual machine: There are 30,000 memory cells of unsigned bytes (values 0 to 255) initialized to 0. There is a cell counter initialized to point at cell 0.

The instructions on the die are as follows:

  • 1 is + (increments current cell by 1)
  • 2 is - (decrements current cell by 1)
  • 3 is > (increments cell count by 1)
  • 4 is < (decrements cell count by 1)
  • 5 is [ (begins a loop)
  • 6 is ] (ends a loop)

Drinking rules

Each player takes turn and rolls a die. The die changes the state of the machine, and the current player announces the outcome. If the current player says something wrong, the other players correct him/her and a sip is taken.

Overflow

In case a cell is reduced below 0 or increased above 255, the value wraps around and a sip is taken.

If a cell is reduced to 0 in any way, a sip is taken. It is also okay to say underflow to remark the direction, even though the term refers to a different phenomenon.

If the cell count is increased above 29,999 or below 0, a sip is taken. This may be referred to as cell count overflow (or underflow).

Syntax error

It might occur that a 6 is rolled before a 5. This is not a legal Brainfuck program, so a sip is taken, but the game continues with the same state. (It is too easy to produce syntax errors to start over.)

Resolving loops

Loops are difficult – probably a bit too difficult for a drinking game, but at the same time the source of the challenge of playing.

When a 5 is rolled, a loop is entered. Instructions within a loop are not evaluated before the loop is ended with the roll of a 6, or when someone can determine what the loop will inevitably do. This can be called short-circuiting or optimizing it.

To resolve a loop, one first looks at the current cell and asks, “is it zero?” If not, the loop is evaluated once, and the question is asked again. Nested loops get hairy, especially when drunk.

Loop optimization

If the current cell is zero to begin with, one may say that whatever is within the loop would be discarded the moment the loop ends, so the roll may be ignored (optimized away).

Similarly, if one creates a nested loop and realizes that the nested loop is infinite, this ends the game as well as a top-level infinite loop. This is the case of unreachable code.

An infinite loop causes the game to reset and the current player to bottom up. Similarly, if a loop causes a person to drink a very large amount of sips that isn’t infinite, they may simply bottom up, and depending on the complexity of the state, the machine may be reset.

Example play

P, Q and R are sitting at a table.

P rolls a 1 and says “plus one!”

Q rolls a 1 and says “plus one! cell 0 is now at 2.”

R rolls a 3 and says “Register 1 at value 0!”

P rolls a 5 and says “Loop, but optimized away.”

Q rolls a 2 and says “Underflow!” and takes a sip.

R rolls a 6 and says “Syntax error!” and takes a sip.

P rolls a 4 and says “Register 0 at value 2.”

Q rolls a 5 and says “Loop begins.”

R rolls a 2 and says “Minus one, but not yet.”

P rolls a 1 and says “Plus one cancels out minus one.”

Q rolls a 5 and says “Nested loop!”

R rolls a 6 and says “The nested loop will be infinite!” and bottoms up.

Observations

There can be many types of games. It can be quite hard to remember a large loop before it is evaluated, and it seems like a loss of quality to have to write down the program or even the states.

Nevertheless, playing a few rounds might impress your non-CS friends with how nerdy you really are. I’m not sure if that’s a good thing.