Info

Stars:
Downloads: 801
Languages: English
Added: 04.08.2014
C#

BefunUtils

BefunUtils

This is my collection of tools, libraries and transcompilers for the esoteric programming language Befunge.

It consists of the following core components:

BefunGen:

A Befunge-93 to multiple procedural languages (c, java, csharp, python) transcompiler

BefunWrite:

A small editor for Textfunge, the language used by BefunGen - use this if you want to try BefunGen for yourself

BefunHighlight:

A dynamic Befunge-93 syntax highlighting library. Highlights your sourcecode intelligent and context-sensitive

BefunExec:

A (fast) Befunge-93 interpreter and debugger

BefunRep:

A tool to calculate (the best) number-representation in Befunge-93 space

BefunCompile:

An (non-general) Befunge-93 compiler. Compile your Befunge-93 code to C, C# or Python

BefunRun:

A simple terminal tool to run a befunge93 program (with extended grid size) and output its output.

BefunDebug:

A debug and test tool for BefunGen, BefunCompile, BefunHighlight, etc

Set up

You can either download the binaries from www.mikescher.com.

Or you can setup the Solution by yourself:

  • Clone the BefunUtils repository
  • Clone all the subproject repositories into subfolder (or simply execute CLONE_ALL.bat)
  • (eg clone BefunExec into the folder /BefunExec)
  • Open the solution file in Visual Studio (or build all projects with the BUILD_ALL.bat script)

Screenshots

BefunExec:

BefunWrite:

BefunRep:

BefunHighlight:

BefunCompile:

BefunCompile (Graph display of Euler_Problem-002 Level 0) (via BefunDebug):

BefunCompile (Graph display of Euler_Problem-002 Level 2) (via BefunDebug):

BefunCompile (Graph display of Euler_Problem-002 Level 3) (via BefunDebug):

BefunCompile (Graph display of Euler_Problem-002 Level 5) (via BefunDebug):

BefunExec is a fast Befunge-93 interpreter.

BefunExec can either be controlled over the menu or by keyboard shortcuts. You can read about the shortcuts and the command line parameters in the console window of BefunExec.

Program

In the center you can see the program, depending on your options highlighted or not.
You can zoom in either with your mouse wheel or by dragging a selection box. With Esc can you go one zoom level back. By pressing R can you reset the whole program and by pressing Space can you pause/un-pause it.
While he program s paused you can do a single step by pressing Left
You can also change the simulation speed with the shortcuts 1 to 5 and add breakpoints by clicking on a single command (breakpoints are displayed blue).

Tip:
Access debug information like FPS and your current interpretation speed by holding tab

Stack

On the left side is the current program stack, if you have enabled it you can see behind the numbers the ASCII representation of the number.

In/Output

Every output is written into the output field and the console, you can also access all the output over the menu entry "show output".

For the input there is an input buffer in place. You can enter a series of chars in the input-box and press the input button. Your text is then in the input buffer and the next time the program wants to read a character it will take it from this buffer. If the buffer is empty the program will pause until there is a character in it which it can read.

When the programs reads a number on the other side will always pause the program and ask the user to enter a number.

Settings

Over the menu you can change a few settings:

  • Syntax Highlighting: Choose your Syntax highlighting method
  • Follow cursor: Zoom in and follow the PC automatically around
  • Show trail: Show trail behind PC
  • ASCII stack: Show ASCII characters in stack display
  • Skip NOP's: Skip continuous White spaced
  • Debug mode: While in debug mode you will be warned of operations that would never occur in a BefunGen created program (wrap-around-edge, pop empty stack ...)

Extended Syntax Highlighting

BefunExec can use BefunHighlight to highlight the program (= extended Syntax highlighting).
It will automatically choose so if the program isn't too big and you haven't explicitly specified another highlighting method. Be aware that when you run on top speed and BefunExec is getting slowed down a lot by BefunHighlight it will automatically change the highlighting method.

BefunRep is an command line tool to calculate Befunge93 number representations

To execute BefunRep you need to open the windows command line (cmd.exe).

The representations are saved in a "safe", you can give the safe-path with the parameter safe. There are three safe-formats available: binary (.bin), CSV (.csv) and JSON (.json). But for most cases the binary safe is the best, especially for bigger safes.

When you first generate a safe you have to give him a number range with the parameters lower and upper

> BefunRep -safe="binsafe.bin" -lower=0 -upper=1000 -reset

The reset command resets the safe if the file already exists.

You can update an existing safe and search for improvements

> BefunRep -safe="binsafe.bin"

Here the existing limits in the safe are re-used. But you can also extend a safe and give him a new range.

> BefunRep -safe="binsafe.bin" -lower=-100 -upper=3500

As you can see with every iteration on the same range there is a chance to find a few improvements. You can also specify a fixed amount of iterations with the parameter iterations. A negative iteration number will result in calculations until no more improvements can be found.

> BefunRep -safe="binsafe.bin" -reset -lower=-100 -upper=3500 -iterations=-1

When you calculate a new safe you will get a lot of console output, this will probably slow your program down. The parameter quiet (or just q) prevents the "Found improvement" output. Also you can specify a statistics level from 0 to 3 with stats, this regulates the safe statistics you can see at the end of the program.

> BefunRep -safe="binsafe.bin" -reset -lower=-100 -upper=3500 -iterations=-1 -q -stats=3

If you already have an safe and don't want to calculate anything so you only see its statistics you can use iterations=0

> BefunRep -safe="binsafe.bin" -iterations=0 -stats=3

The binary safe format is not really human readable, to get the results in a better format use the out parameter. Supported formats are CSV (.csv), JSON (.json) and XML (.xml). XML and JSON are useful to redirect it to other programs and CSV to manually read them, because CSV doesn't need to escape any characters.

> BefunRep -safe="binsafe.bin" -reset -lower=-100 -upper=3500 -iterations=-1 -q -out="csvoutput.csv"

Similiar to the statistics you can also use the iterations=0 trick to generate an output of an existing safe

> BefunRep -safe="binsafe.bin" -iterations=0 -out="csvoutput.csv"

Internally BefunRep has multiple algorithms that are executed one after the other. Normally all are executed but you can also specify a single one to use with the parameter algorithm

> BefunRep -safe="binsafe.bin" -reset -lower=-100 -upper=3500 -algorithm=3

If you need a list of the possible arguments execute BefunRep without any arguments or with help

> BefunRep -help

BefunWrite is an IDE to write and compile TextFunge, once started you will see the main window:

You can write your code in the center and see a summary of current constants/variables/methods on the right side. On the bottom site you can also expand the tabs Output and ErrorList.

In the code section you can see an example program (a simple hello world), feel free to edit this example or delete it completely. You can safe your code in the menu or by pressing STRG+S. 3 different files will be created:

  • projectname.tfp : The project file, it contains settings and the path to the other files
  • projectname.tf : The actual source-code
  • projectname.tfdv : The initial display value (or empty if not defined)

If you want to set an initial display value (see the topic TextFunge for more information) you can modify the tab Display beside the tab code. To build the project simply choose a build configuration (Debug and Release are the defaults) and click Build. The builded Befunge files will end up in the sub-folder projectname\configname.
To test the program you can also choose run, this will build the project and then open it in BefunExec.

Build configurations

With the build configurations dialog you can modify the build process

BEFUNWRITE_SETTINGS

Note:

  • PC is the Program Counter, the current position in the program
  • NOP-cells are the unused parts of the program, they are neither variable space, nor commands.
    The PC will enter them and they should never be evaluated.

General

General BefunWrite Settings

  • Name

Execution

BefunExec Settings

  • Debugging Enabled: Enable debugging options (warnings on unexpected behaviours)
  • Start Paused: Starts the program non-running
  • Syntax highlighting: Sets the preferred syntax highlighting method
  • Show chars in stack: Show the ASCII chars in the stack
  • Follow PC: Start with follow mode enabled
  • Skip Whitespace: Skip continuous white-spaces
  • Initial speed: Sets (the index) of the initial interpretation speed
  • Speed[x]: The delay between cycles on speed level x
  • Show Tail: Show a fading tail behind the actual PC
  • Lifetime Tail: The time (in ms) until the tail has faded away
  • Start zoomed in on display: Set the initial zoom fitting for the display

Code Generation

BefunGen Settings

  • Number literal representation: The used algorithm for presenting number literals
  • Optimize double string-mode: Try to combine two adjacent " together
  • Set NOP to special char: Set NOP cells to a special character
  • Custom NOP char: The special character for NOP cells (if used)
  • Horizontal compression: Try to horizontally compress the program
  • Vertical compression: Try to vertically compress the program
  • Minimum VarDecl. width: The minimum width of a declaration block, increase this if your initialization-blocks grow in height.
  • Default VarDecl char: The initial char (before initialization) of variable fields
  • Default TempDecl/TempResult char: The initial char (before use) of temporary fields
  • Safe boolean cast: When hard-casting a variable to boolean it will result in either a 1 or a 0
  • Default local int/char/bool var value: The initial value of a local variable (should stay default)
  • Initial disp char: The initial character of the display fields
  • Display border value: The character of the border around the display
  • Display border thickness: The thickness of the border around the display
  • Prevent Display overflow: When accessing coordinates outside of the display wrap around the edges.
  • Optimize static Expr: Try to compile-time interpret simple expressions (4 * 4 + 4 ==> 20)
  • Remove unused methods: Don't include methods that get never called

    Warning ! If Prevent Display overflow is not set you can write into your own program and cause really strange behaviour.
    If you choose this path you have to prevent an out-of-bounds display access for yourself.

    Be aware that it is wise to leave most code generation settings on their default values.
    For the most cases only the settings Set NOP to special char, Safe boolean cast and Prevent Display overflow should be interesting.

TextFunge is the c-like language used for BefunGen.
Most constructs are very similar to C and Pascal, so you won't have trouble writing anything in it.

Note:
TexFunge programs are case-insensitive. (but please be consistent with your naming)

Program structure

A TextFunge program starts with the keyword program and the program name and ends with end

program example_01 : display[0, 0]
    begin
        // code
    end

    void method()
    begin
        // code
    end
end

between programandend` you can put your methods. The first method has no header and is called the main method. This method is called upon the beginning and when this method has finished the program terminates.

You can specify a display by writing : display[width, height], if the display is not specified its has a width and height of zero.

Types

TextFunge knows 9 different variable types:

  • Integer: A single integer value
  • Digit: A single Base-10 digit (integer in the range from 0 to 9 )
  • Character: A single character
  • Boolean: A boolean value (TRUE or FALSE)
  • Void: Nothing, used for methods that return nothing
  • Integer Array: An fixed-length array of multiple integer
  • String: An fixed-length array of multiple character
  • Digit Array: An fixed-length array of multiple digits
  • Boolean Array: An fixed-length array of multiple booleans
int a1;
integer a2;
int[4] a3;

char b1;
character b2;
character[4] b3; 

bool c1;
boolean c2;
bool[4] c3; 

digit d1;
digit[4] d2; 

You can freely cast all value types into each other and all array-types with the same length (see Casts for more information)

Variables

Between each method header and the begin keyword you can specify local variables under the var keyword:

void method()
var
    int var_1, var_2;
    int var_3     := 77;
    int[4] var_4  := {0, 1, 1, 0};
    char[4] var_5 := "FFFF";
begin

These variables have a local scope and can't be accessed from anywhere else.

You can also at the beginning of the program specify variables with a global scope

program example_02
global
    int gvar_1, gvar_2;
    int gvar3;

Note:
Global variables (unlike local variables) can not have an initializer, they will initially have the value which you specified while compiling.

To access a variable as whole just write its name, to access an specific array index write the index in square brackets:

var_1[0] = var_2[4 + 1];

Constants

At the same position as global variables can (global) constants be defined:

program example_02
const
    int VERSION := 14;
    int COL_BLUE := 0x0000FF;
    char UNDERSCORE := '_';

Be aware that constants are always in the compiled program inlined. So constants are only syntactical sugar and result in the same as writing the literal everywhere, where you use the constant.

Note:
You can only define constants for value types, array constants are not yet supported.

Literals

You can specify (Base-10) integer literals by simply writing the number:

0
9283
-9283

And also Base-16 (Hexadecimal) integer literals with 0x

0x00
0xF0F
0x123

Digit literals have a # prefix:

#0
#6
#9

Char literals are surrounded by single ticks:

' '
'A'
'a'

Boolean literals consist of the two boolean keywords:

true
false
TRUE

String literals are surrounded by quotation marks: (Be aware that a string literal is only a shortcut notation of an char array)

""
"hello"
"hello \r\n second line"

And Array literals are the values inside of a set of curly braces:

{0, 1}
{'h', 'e', 'l', 'l', 'o'}
{true, false, true}

Methods

Methods consist of 2 parts, the header and the body:

int[9] method(int a, int b, int[9] c)
var
    int var_1 := 0;
    int var_2;
begin
    // Code
    // Code
    // Code

    return c;
end

In the header you define the return type (value type, array type or void), the method name (the normal C naming restriction are valid) and the parameter list (multiple value or array types).

Then you can (optionally) define local variables.

And finally between begin and end you can write your code.

Note:
Every path of an method must result in an return statement.
If the return type is void the compiler can automatically add an return to the end.

Control Structures

If / Elsif

if (a) then
    // Code [a == true]
elsif (b) then
    // Code [b == true]
elsif (c) then
    // Code [c == true]
else
    // Code [else]
end

You can write a branch statement with the keyword if.
Unlike C you have to write additional else if-branches with the keyword elsif and you have to end the whole block with end

While do

The while loop repeats a statement block until a condition is false

while (running) do
    // Code
end

Every loop the condition is evaluated and checked.

Repeat until

The repeat until loop repeats a statement block until a condition is true

while (running) do
    // Code
end

The difference to a while loop is that the condition is executed at least once.

For

The for loop is a more comfortable loop, because it has an initializer field, a condition field, and a statement field

//  (init ; cond  ; stmt)
for (i = 0; i < 10; i++ ) do
    // Code
end

Each field can also be empty, allowing for this simple, infinite loop:

for (;;) do
    // Code
end
// <-- unreachable (without goto)

Switch case

If you want to distinct multiple values you can use a switch statement:

switch(c)
begin
    case ' ':
        // Code
    end 
    case '0':
        // Code
    end
    default:
        // Else-Code
    end
end

Note:
This is not C, there is no fall-through with empty case blocks.

Note:
Having a lot of cases in a single switch can increase the horizontal size of your program drastically. Think about using other possibilities in this case

Goto

goto MLBL;
out "Nobody sees me";
MLBL:
out "end";

You can define labels by writing the identifier and a colon (instead of a semicolon).
And you can write goto statements with the keyword goto

Note:
This is not C, you have to end an goto statement with an semicolon, like every other statement too.

Note:
Use goto's sparely, they are pretty slow and I'm not sure if they are bug-free.

Expressions

Mathematical operators

You can use the normal mathematical operators +, -, *, /, % (modulo), ( and ).
Normal precedence rules apply

a = ((5 + 5)*4 - 10)/-1 % 4;

Boolean operators

You can use the boolean operators && (AND), || (OR), ^ (XOR), ! (NOT).

a = (10 == x) ^ true;
b = !(10 == x);

Comparison

You can use the normal c-like comparison operators ==, !=, <, >, <= and >=

while (a < 100 && a > -100) do
    a *= 2;
end 

Special Statements

Random

You can either generate a random boolean value by using rand, or a random integer value by using rand[?].

rand[n] generates a random number from [0, 4^n), where 0 is included and 4^n is excluded. So you are only able to set the upper border to results of the formula 4^n.

if (rand) do
    a = rand[6] % 10;
end 

Note:
Be aware that in the example above not all values are equally distributed (4^6 % 10 != 0), but approximately it is good, and it becomes better with bigger values for n.

Quit

The statement quit, stop or close instantly terminates the program. The main method will always implicitly have an quit at the end.

if (error != 0) then
    out "FATAL ERROR";
    quit;
end

Code block

You can start everywhere a new code block, it probably wont change the resulting program but has its use in structuring the source code.

// Code
begin
    // Code
    // Code
end
// Code

De-/Increment

With ++ and -- you can increment/decrement a variable in a shorter way than a assignment.

a++;
a = a + 1; // equally

Assignments

With a single = you can assign a value to a variable.

a = 3;
b[3] = 0;

Method calls

Method calls are pretty much like in every other language.

method_1(0, 6, "hello");
method_2(getA(), getB(0));

Comments

You can write either full line comments with // or block comments with /* and */

/* Comment
 * Comment
 */

// Comment

method_99( /* comment */ ); 

Casts

TextFunge supports explicit and implicit casting.

The cases in which implicit casts happen are:

  • digit -> int
  • digit[] -> int[] (with same length)

You can cast all other value types into each other and array types if they have the same length.

var
    bool b;
    int i;
    char c;
begin
    c = (char)i;
    b  = (bool)c;

Note:
When casting no information is lost, so hard casting to an digit can yield to an illegal value.
Also casting something from an boolean does not always result in 0 or 1 (it results in 0 / not 0). If you want this you can enable "explicit boolean casting" in the compiler options.

Input/Output

Out

With the statement out you can output either a value or a string:

out 99;
out 'a';
out "Hello World";
out var_1;

OutF

Outf is a shortcut to writing multiple out statement. You can give it a comma-separated list of expressions to output

out 99, 'a', "Hello World", var_1;

In

With the In Statement you can ask the user for a value, the input routine differs when you give it a integer variable or a character variable.

var
    int var_1;
    char var_2;
begin
    in var_1; // Asks for number
    in var_2; // Asks for character

In TextFunge you can optionally define a read- and writable display area.

program example_01 : display[16, 16]

The display has a width and a height and every field has initially the value you set in the options (the standard is space).

You can access the display with the display[x, y] command.

display[0, 0] = 'X'; // Write 'X' to position (0,0)
c = display[0, 1];   // Set c to the value of (0,1)

There are also a few automatically defined constants for teh work with displays:

DISPLAY_WIDTH // The width of the display
DISPLAY_HEIGHT // The height of the display
DISPLAY_SIZE // The size (width*height) of the display

You can use the display to

  • display information to the user without using input commands
  • gather a big amount of data from the user before execution (he has to fill the display manually)
  • use it as a big 2-dimensional array for calculations

Note:
Beware that there is normally no mechanism to control access overflow.
So you can enter to high/low x/y values and access/modify program pieces that are not part of the display.
This is a way of bricking your program by writing in the area of program code

Tip:
You can prevent this by enabling the compiler option Prevent display overflow. But beware that tis will result in longer display access times.

There are a few things you should consider when creating programs with Befunge:

Number ranges

The size of the internal numbers is dependent on the interpreter, while you can safely assume that the number is at least 16bit, everything higher is not sure. So for bigger programs you have to either work with smaller numbers or use interpreters which use bigger sizes.

Tip:
BefunExec uses 64bit integer (= long values).

Negative numbers

A real problem are negative numbers. In created programs variables are saved in the grid. If the interpreter does not support negative grid values you will not be able to use negative numbers.

But don't worry too much - most interpreters I know support negative numbers in the grid.

Performance

BefunGen is definitely not a tool to create fast Befunge programs, it's a tool to create big ones.
And while it optimize your program quite a bit, a manual written program will always be faster and smaller.

So for bigger programs you will also need an fast interpreter - otherwise the execution could take a long time

Tip:
BefunExec is a pretty fast multi-threaded interpreter.

Program size

While the generated programs are strictly bound to the Befunge-93, they can become pretty big (bigger than 80x25).

So you have to either use a Befunge-93 interpreter which ignores the size limit (many interpreters do that) or use a Befunge-98 interpreter.

Tip:
BefunExec, as you probably can assume, has no "real" size limit to it.

Here a few tricks for programming with BefunGen:

Horizontal size

Normally a program only grows in height, the more instructions your program has the greater is the height of the generated code.

So it is kinda bad when you have one really long line, because the width of the program is determined by the longest line. So its good to try to avoid long lines for the sake of smaller - more compressed programs.

Here are a few common cases which compile to long single lines:

  • Deep Nesting (e.g. multiple nested for loops)
  • A lot of consecutive elsif statements
  • Switch statements with a lot of cases
  • Function calls with a lot of parameters
  • Very long arrays
  • Complex "one-line" statements (e.g. multiple nested method calls)

Neither of these things has any real consequence - except your program having a lot of empty space.

Display as array

If you are in need of a really big array, or of a 2 dimensional array you can use the display for that.

The display is an easy way of having an global 2dimensional array, that is easily visible to the user.

Constants

You can without hesitation use constants in your program, they are inlined on compilation and have no performance cost at all.

Hello World

A simple "Hello World"

program example
    begin
        out "Hello World\r\n";
        quit;
    end
end

Note: This and other examples are included in the BefunGen download

Sieve of Erasthothenes

Calculates the primes between 0 and 19200 with the sieve of Erasthothenes

program SieveOfEratosthenes : display[240, 80]
    begin
        // Init all Fields with '?'
        init(); 

        // Set an 'X' to every Primenumberfield
        calculate();

        // Output the primes
        output();
    end

    void init()
    var 
        int i;
    begin
        for(i = 0; i < DISPLAY_SIZE; i++) do
            display[i % DISPLAY_WIDTH, i / DISPLAY_WIDTH] = '?';
        end

        display[0, 0] = ' ';
        display[1, 0] = ' ';
    end

    void calculate()
    var 
        int i;
    begin
        for(i = 2; i < DISPLAY_SIZE; i++) do
            doNumber(i);
        end
    end

    void doNumber(int i) 
    var
        char c;
    begin
        c = display[i % DISPLAY_WIDTH, i / DISPLAY_WIDTH];

        if (c == 'X' || c == ' ') then
            return;
        elsif (c == '?') then
            display[i % DISPLAY_WIDTH, i / DISPLAY_WIDTH] = 'X';

            clear(i);
        end
    end

    void clear(int n)
    var
        int p;
    begin
        for(p = 2*n; p < DISPLAY_SIZE; p += n) do
            display[p % DISPLAY_WIDTH, p / DISPLAY_WIDTH] = ' ';
        end
    end

    void output()
    var
        int i;
    begin
        out "Prime Numbers:\r\n";
        for(i = 2; i < DISPLAY_SIZE; i++) do
            if (display[i % DISPLAY_WIDTH, i / DISPLAY_WIDTH] == 'X') then
                outf i, "\r\n";
            end
        end
    end
end

Note: This and other examples are included in the BefunGen download

The Euclidean algorithm

A simple, recursive implementation of the euclidian algorithm

program EuclidianAlgo
    var
        int a, b, eucl;
    begin
        out "Please insert numer [a]\r\n";
        in a;
        out "Please insert numer [b]\r\n";
        in b;

        eucl = euclid(a, b);

        outf "euclid(", a, ",", b, ") = ", eucl, "\r\n";

        outf a, "/", b, " = ", (a/eucl), "/", (b/eucl), "\r\n";

        quit;
    end

    int euclid(int a, int b) 
    begin
        if (a == 0) then
            return b;
        else 
            if (b == 0) then
                return a;
            else 
                if (a > b) then
                    return euclid(a - b, b);
                else
                    return euclid(a, b - a);
                end
            end
        end
    end
end

Note: This and other examples are included in the BefunGen download

Fibonacci numbers

Calculates the Fibonacci sequence

program Fibbonacci
    var
        int i;
    begin
        out "Input the maximum\r\n";
        in i;

        doFiber(i);
        quit;
    end

    void doFiber(int max)
    var
        int last := 0;
        int curr := 1;
        int tmp;
    begin
        repeat
            if (last > 0) then
                out ",";
            end

            out curr;

            tmp = curr + last;
            last = curr;
            curr = tmp;
        until (last > max)
    end
end

Note: This and other examples are included in the BefunGen download

Fizz Buzz

A simple implementation of the Fizz Buzz game.

program FizzBuzz
    begin
        fizzbuzz();
        quit;
    end

    void fizzbuzz()
    var
        int i := 0;
    begin
        i = 1;

        while (i < 100) do
            if (i % 3 == 0 && i % 5 == 0) then
                out "FizzBuzz";
            elsif (i % 3 == 0) then
                out "Fizz";
            elsif (i % 5 == 0) then
                out "Buzz";
            else
                out i;
            end

            out "\r\n";

            i++;
        end
    end
end

Note: This and other examples are included in the BefunGen download

PI Calculation

Calculates PI to a certain degree with the Monte Carlo algorithm

program PICalc : display[256, 256]
    const
        // WIDTH = HEIGHT = 4^SIZE
        int SIZE := 4; 

        // Total Count
        int COUNT := 65536;

        // After n Steps print out intermediate result
        int STEPS := 4096;

    global
        int hit;
        int miss;
    var
        int i;
    begin
        hit = 0;
        miss = 0;

        for(i = 0; i < COUNT; i++) do
            drop();

            if (i % STEPS == 0) then
                output();
            end
        end

        output();
    end

    void output()
    begin
        // PI := (4 * hit)/(total)
        outf "PI = ", (4*hit), "/", (hit+miss), " = ", floatDiv(4 * hit, miss + hit), "\r\n";
    end

    void drop()
    var
        int x, y;

        char c;
    begin
        x = RAND[SIZE];
        y = RAND[SIZE];

        c = display[x, y];

        display[x, y] = 'X';

        if (c == '#') then
            hit++;
        elsif (c == ' ') then
            miss++;
        else
            out "FATAL ERROR 0x01";
        end

        display[x, y] = c;
    end

    // Gives a string containing a/b as float back
    char[10] floatDiv(int a, int b)
    var
        char[10] result;
        int mantissa;
        int pos := 0;
    begin
        mantissa = a / b;

        repeat
            if (pos == 10) then
                return result;
            end

            result[pos++] = (char)((int)'0' + (mantissa % 10));
            mantissa /= 10;
        until (mantissa == 0)

        if (pos == 10) then
            return result;
        end
        result[pos++] = ',';

        for(;;) do
            if (pos == 10) then
                return result;
            end

            a %= b;
            a *= 10;
            result[pos++] = (char)((int)'0' + (a / b));
        end

        return result;
    end
end

Note: This program needs a special initial display value to work - see the download to execute it.

Note: This and other examples are included in the BefunGen download

Befunge-93 interpreter

An Befunge-93 interpreter

program BefInterpreter : display[60, 30]
    const
        int STACKSIZE := 16;
    global
        int[4] DELTA_IDX_X;
        int[4] DELTA_IDX_Y;

        bool running;

        int PC_X;
        int PC_Y;

        int D_X;
        int D_Y;

        bool stringmode;

        int[16] stack;
        int stackHead;
    begin
        Init();

        while (running) do
            execute();
            move();
        end

        quit;
    end

    void Init()
    begin
        DELTA_IDX_X[0] =  1;
        DELTA_IDX_X[1] =  0;
        DELTA_IDX_X[2] = -1;
        DELTA_IDX_X[3] =  0;

        DELTA_IDX_Y[0] =  0;
        DELTA_IDX_Y[1] = -1;
        DELTA_IDX_Y[2] =  0;
        DELTA_IDX_Y[3] =  1;

        stackHead = 0;

        PC_X = 0;
        PC_Y = 0;

        D_X = 1;
        D_Y = 0;

        stringmode = false;

        running = true;
    end

    void execute()
    var
        char c;

        int tmp, tmp2, tmp3;
    begin
        c = display[PC_X, PC_Y];

        if (stringmode && c != '"') then
            push((int)c);
            return;
        end

        switch(c)
        begin
            case ' ':
                // NOP
            end 
            case '0':
                push(0);
            end
            case '1':
                push(1);
            end
            case '2':
                push(2);
            end
            case '3':
                push(3);
            end
            case '4':
                push(4);
            end
            case '5':
                push(5);
            end
            case '6':
                push(6);
            end
            case '7':
                push(7);
            end
            case '8':
                push(8);
            end
            case '9':
                push(9);
            end
        end

        switch(c)
        begin
            case '+':
                push(pop() + pop());
            end
            case '-':
                tmp = pop();
                push(pop() - tmp);
            end
            case '*':
                push(pop() * pop());
            end
            case '/':
                tmp = pop();
                push(pop() / tmp);
            end
            case '%':
                tmp = pop();
                push(pop() % tmp);
            end
            case '!':
                push((int)(!popBool()));
            end
            case '`':
                tmp = pop();
                push((int)(pop() > tmp));
            end
            case '>':
                D_X = 1;
                D_Y = 0;
            end
            case '<':
                D_X = -1;
                D_Y = 0;
            end
            case '^':
                D_X = 0;
                D_Y = -1;
            end
            case 'v':
                D_X = 0;
                D_Y = 1;
            end
            case '?':
                tmp = RAND[1];
                D_X = DELTA_IDX_X[tmp];
                D_Y = DELTA_IDX_Y[tmp];
            end
        end

        switch(c)
        begin
            case '_':
                if (popBool()) then
                    D_X = DELTA_IDX_X[2];
                    D_Y = DELTA_IDX_Y[2];
                else
                    D_X = DELTA_IDX_X[0];
                    D_Y = DELTA_IDX_Y[0];
                end
            end
            case '|':
                if (popBool()) then
                    D_X = DELTA_IDX_X[1];
                    D_Y = DELTA_IDX_Y[1];
                else
                    D_X = DELTA_IDX_X[3];
                    D_Y = DELTA_IDX_Y[3];
                end
            end
            case '"':
                stringmode = !stringmode;
            end
            case ':':
                push(peek());
            end
            case '\\':
                tmp = pop();
                tmp2 = pop();
                push(tmp);
                push(tmp2);
            end
            case '$':
                pop();
            end
            case '.':
                out pop();
            end
            case ',':
                out popChar();
            end
            case '#':
                move();
            end
            case 'g':
                tmp = pop();
                tmp2 = pop();
                if (tmp >= 0 && tmp2 >= 0 && tmp2 < DISPLAY_WIDTH && tmp < DISPLAY_HEIGHT) then
                    push((int)display[tmp2, tmp]);
                else
                    push(0);
                end
            end
            case 'p':
                tmp = pop();
                tmp2 = pop();
                if (tmp >= 0 && tmp2 >= 0 && tmp2 < DISPLAY_WIDTH && tmp < DISPLAY_HEIGHT) then
                    display[tmp2, tmp] = popChar();
                else
                    pop();
                end
            end
            case '&':
                in tmp;
                push(tmp);
            end
            case '~':
                in tmp3;
                push((int)tmp3);
            end
            case '@':
                out "\r\n\r\n >> FINISHED";
                running = false;
            end
            default:
                // NOP
            end
        end
    end

    void move()
    begin
        PC_X += D_X + DISPLAY_WIDTH;
        PC_Y += D_Y + DISPLAY_HEIGHT;

        PC_X %= DISPLAY_WIDTH;
        PC_Y %= DISPLAY_HEIGHT;
    end

    void push(int v)
    begin
        stack[stackhead++] = v;
    end

    int pop()
    begin
        if (stackhead == 0) then
            return 0;
        end

        return stack[--stackhead];
    end

    char popChar()
    begin
        return (char)pop();
    end

    bool popBool()
    begin
        return (bool)pop();
    end

    int peek()
    begin
        if (stackhead == 0) then
            return 0;
        end

        return stack[stackhead - 1];
    end
end

Note: This and other examples are included in the BefunGen download

Sudoku Generator

Generates a random (but valid) Sudoku puzzle

program SudoGen : display[17, 17]
    const
        char CHR_EMPTY     := ' ';
        char CHR_UNKNOWN   := ' ';
        char CHR_BORDER    := '#';
        char CHR_INTERSECT := '+';
        char CHR_HORZ      := '-';
        char CHR_VERT      := '|';
    begin
        Init();

        Create();

        Obfuscate();
    end

    void Init()
    var
        int x, y;
    begin
        for (y = 0; y < DISPLAY_HEIGHT; y++) do
            for (x = 0; x < DISPLAY_WIDTH; x++) do
                if (x % 2 == 0 && y % 2 == 0) then
                    display[x, y] = CHR_EMPTY;
                elsif ((x + 1) % 6 == 0 || (y + 1) % 6 == 0) then
                    display[x, y] = CHR_BORDER;
                elsif ((x - 1) % 2 == 0 && (y - 1) % 2 == 0) then
                    display[x, y] = CHR_INTERSECT;
                elsif ((x - 1) % 2 == 0 && y % 2 == 0) then
                    display[x, y] = CHR_VERT;
                elsif (x % 2 == 0 && (y - 1) % 2 == 0) then
                    display[x, y] = CHR_HORZ;
                end
            end
        end
    end

    bool Create()
    var
        int x, y;

        int on;
        int n;
    begin
        if (!IsValid()) then
            return false;
        end

        on = rand[3] % 9;

        for (y = 0; y < 9; y++) do
            for (x = 0; x < 9; x++) do
                if (display[x * 2, y * 2] == CHR_EMPTY) then
                    for (n = 0; n < 9; n++) do
                        display[x * 2, y * 2] = (char)((int)'1' + ((n + on) % 9));

                        if (Create()) then
                            return true;
                        end

                        display[x * 2, y * 2] = CHR_EMPTY;
                    end

                    return false;
                end
            end
        end

        return true;
    end

    bool IsValid()
    var
        int x, y;
        int p;
        int c;
        int[9] vals;
    begin
        // Rows

        for (y = 0; y < 9; y++) do
            for (p = 0; p < 9; ) do
                vals[p++] = 0;
            end

            for (x = 0; x < 9; x++) do
                if (display[x * 2, y * 2] != CHR_EMPTY) then
                    vals[((int)display[x * 2, y * 2]) - ((int)'1')]++;
                end
            end

            for (p = 0; p < 9; p++) do
                if (vals[p] > 1) then
                    return false;
                end
            end
        end

        // Cols

        for (x = 0; x < 9; x++) do
            for (p = 0; p < 9; ) do
                vals[p++] = 0;
            end

            for (y = 0; y < 9; y++) do
                if (display[x * 2, y * 2] != CHR_EMPTY) then
                    vals[((int)display[x * 2, y * 2]) - ((int)'1')]++;
                end
            end

            for (p = 0; p < 9; p++) do
                if (vals[p] > 1) then
                    return false;
                end
            end
        end

        // Rects

        for (c = 0; c < 9; c++) do
            for (p = 0; p < 9; ) do
                vals[p++] = 0;
            end

            for (x = (c / 3) * 3; x < (c / 3 + 1) * 3; x++) do
                for (y = (c % 3) * 3; y < (c % 3 + 1) * 3; y++) do
                    if (display[x * 2, y * 2] != CHR_EMPTY) then
                        vals[((int)display[x * 2, y * 2]) - ((int)'1')]++;
                    end
                end
            end

            for (p = 0; p < 9; p++) do
                if (vals[p] > 1) then
                    return false;
                end
            end
        end

        return true;

    end

    bool isRemovable(int x, int y)
    var
        int v;
        int p;
        int rx, ry;
        bool[9] vals;
    begin

        v = ((int)display[x * 2, y * 2]) - ((int)'1');

        for (p = 0; p < 9; ) do
            vals[p++] = false;
        end

        // Row
        for (p = 0; p < 9; p++) do
            if (display[p * 2, y * 2] != CHR_UNKNOWN) then
                vals[((int)display[p * 2, y * 2]) - ((int)'1')] = true;
            end
        end

        // Col
        for (p = 0; p < 9; p++) do
            if (display[x * 2, p * 2] != CHR_UNKNOWN) then
                vals[((int)display[x * 2, p * 2]) - ((int)'1')] = true;
            end
        end

        //Rect
        for (rx = (x / 3) * 3; rx < (x / 3 + 1) * 3; rx++) do
            for (ry = (y / 3) * 3; ry < (y / 3 + 1) * 3; ry++) do
                if (display[rx * 2, rx * 2] != CHR_UNKNOWN) then
                    vals[((int)display[rx * 2, ry * 2]) - ((int)'1')] = true;
                end
            end
        end

        //Test
        for (p = 0; p < 9; p++) do
            if (!vals[p] && p != v) then
                return false;
            end
        end

        return true;
    end

    void Obfuscate()
    var
        int ox, oy;

        int x, y;
    begin
        ox = rand[3];
        oy = rand[3];

        for (x = ox; x < ox + 9; x++) do
            for (y = oy; y < oy + 9; y++) do
                if (display[(x % 9) * 2, (y % 9) * 2] != CHR_UNKNOWN) then
                    if (isRemovable(x % 9, y % 9)) then
                        display[(x % 9) * 2, (y % 9) * 2] = CHR_UNKNOWN;
                        Obfuscate();
                        return;
                    end
                end
            end
        end

        return;
    end
end

Note: This and other examples are included in the BefunGen download

Conway's Game of Life

A simulation of Conway's Game of Life

program GameOfLife : display[40, 40]
    const
        char FIELD_UNSET := ' ';
        char FIELD_SET := 'O';
        char FIELD_PREBORN := 'o';
        char FIELD_PREDEAD := 'Q';
    begin
        Init();

        Run();
    end

    void Init()
    var
        int x, y;
    begin
        for (x = 0; x < DISPLAY_WIDTH; x++)
        do
            for (y = 0; y < DISPLAY_HEIGHT; y++)
            do
                if (display[x, y] != FIELD_UNSET) then
                    display[x, y] = FIELD_SET;
                else
                    display[x, y] = FIELD_UNSET;
                end
            end
        end
    end

    void Run() 
    var
        int i := 0;
    begin
        for(;;i++) do
            Tick();
            OUTF "Tick Nr " , i ,  "\r\n";
        end
    end

    void Tick()
    var
        int x, y;
        int nc;
    begin
        for (x = 0; x < DISPLAY_WIDTH; x++) do
            for (y = 0; y < DISPLAY_HEIGHT; y++) do
                nc = GetNeighborCount(x, y);

                if (display[x, y] == FIELD_SET) then
                    if (nc < 2) then // Underpopulation
                        display[x, y] = FIELD_PREDEAD;
                    elsif (nc > 3) then // Overcrowding
                        display[x, y] = FIELD_PREDEAD;
                    end
                else
                    if (nc == 3) then // It lives !
                        display[x, y] = FIELD_PREBORN;
                    end
                end
            end
        end

        for (x = 0; x < DISPLAY_WIDTH; x++) do
            for (y = 0; y < DISPLAY_HEIGHT; y++) do
                if (display[x, y] == FIELD_PREBORN) then
                    display[x, y] = FIELD_SET;
                elsif (display[x, y] == FIELD_PREDEAD) then
                    display[x, y] = FIELD_UNSET;
                end
            end
        end
    end

    int GetNeighborCount(int x, int y)
    var
        int r;
    begin
        r = 0;

        r += (int)(display[x - 1, y - 1] == FIELD_SET || display[x - 1, y - 1] == FIELD_PREDEAD);
        r += (int)(display[x + 0, y - 1] == FIELD_SET || display[x + 0, y - 1] == FIELD_PREDEAD);
        r += (int)(display[x + 1, y - 1] == FIELD_SET || display[x + 1, y - 1] == FIELD_PREDEAD);
        r += (int)(display[x - 1, y + 0] == FIELD_SET || display[x - 1, y + 0] == FIELD_PREDEAD);
        r += (int)(display[x + 1, y + 0] == FIELD_SET || display[x + 1, y + 0] == FIELD_PREDEAD);
        r += (int)(display[x - 1, y + 1] == FIELD_SET || display[x - 1, y + 1] == FIELD_PREDEAD);
        r += (int)(display[x + 0, y + 1] == FIELD_SET || display[x + 0, y + 1] == FIELD_PREDEAD);
        r += (int)(display[x + 1, y + 1] == FIELD_SET || display[x + 1, y + 1] == FIELD_PREDEAD);

        return r;
    end
end

Note: This programs needs the options Safe Boolean Convert and Prevent Display Overflow enabled

Note: This and other examples are included in the BefunGen download

Maze Generator

Generates a Maze on the display with the Hunt&Kill algorithm - thens solves is by recursively trying every path

program MazeGen : display[131, 51]
    const
        char CHR_UNSET := '@';
        char CHR_WALL  := '#';
        char CHR_FLOOR := ' ';
        char CHR_PATH  := '+';
    var
        bool succ;
    begin
        Init();

        Create();

        succ = Solve(1, 1, DISPLAY_WIDTH - 2, DISPLAY_HEIGHT - 2);

        if (succ) then
            out "Maze solved";
        else
            out "Fatal Error: Maze could not be solved";
        end
    end

    void Init()
    var
        int x, y;
    begin
        for(x = 0; x < DISPLAY_WIDTH; x++) do
            for(y = 0; y < DISPLAY_HEIGHT; y++) do
                if (x == 0 || y == 0 || x == DISPLAY_WIDTH - 1 || y == DISPLAY_HEIGHT - 1 || (x % 2 == 0 && y % 2 == 0)) then
                    display[x,y] = CHR_WALL;
                ELSE
                    display[x,y] = CHR_UNSET;
                end
            end
        end
    end

    void Create()
    begin
        Kill(1, 1);
    end

    void Kill(int x, int y)
    var
        bool top;
        bool left;
        bool bot;
        bool right;
        int possibleDirections;
        int direction;
    begin
        for(;;) do
            top   = (display[x + 0, y - 1] == CHR_UNSET);
            left  = (display[x - 1, y + 0] == CHR_UNSET);
            bot   = (display[x + 0, y + 1] == CHR_UNSET);
            right = (display[x + 1, y + 0] == CHR_UNSET);

            possibleDirections = 0;
            possibleDirections += (int)top;
            possibleDirections += (int)left;
            possibleDirections += (int)bot;
            possibleDirections += (int)right;

            if (possibleDirections == 0) then
                display[x, y] = CHR_FLOOR;

                Hunt();

                return;
            end

            direction = rand[3] % possibleDirections;

            if (top) then
                if (direction == 0) then
                    if (display[x, y + 1] == CHR_UNSET) then
                        display[x, y + 1] = CHR_WALL;
                    end
                    if (display[x + 1, y] == CHR_UNSET) then
                        display[x + 1, y] = CHR_WALL;
                    end
                    if (display[x - 1, y] == CHR_UNSET) then
                        display[x - 1, y] = CHR_WALL;
                    end
                    display[x, y] = CHR_FLOOR;
                    y--;
                end
                direction--;
            end

            if (left) then
                if (direction == 0) then
                    if (display[x + 1, y] == CHR_UNSET) then
                        display[x + 1, y] = CHR_WALL;
                    end
                    if (display[x, y + 1] == CHR_UNSET) then
                        display[x, y + 1] = CHR_WALL;
                    end
                    if (display[x, y - 1] == CHR_UNSET) then
                        display[x, y - 1] = CHR_WALL;
                    end
                    display[x, y] = CHR_FLOOR;
                    x--;
                end
                direction--;
            end

            if (bot) then
                if (direction == 0) then
                    if (display[x, y - 1] == CHR_UNSET) then
                        display[x, y - 1] = CHR_WALL;
                    end
                    if (display[x + 1, y] == CHR_UNSET) then
                        display[x + 1, y] = CHR_WALL;
                    end
                    if (display[x - 1, y] == CHR_UNSET) then
                        display[x - 1, y] = CHR_WALL;
                    end
                    display[x, y] = CHR_FLOOR;
                    y++;
                end
                direction--;
            end

            if (right) then
                if (direction == 0) then
                    if (display[x - 1, y] == CHR_UNSET) then
                        display[x - 1, y] = CHR_WALL;
                    end
                    if (display[x, y + 1] == CHR_UNSET) then
                        display[x, y + 1] = CHR_WALL;
                    end
                    if (display[x, y - 1] == CHR_UNSET) then
                        display[x, y - 1] = CHR_WALL;
                    end
                    display[x, y] = CHR_FLOOR;
                    x++;
                end
                direction--;
            end
        end
    end

    void Hunt()
    var
     int ox, oy;
     int fx, fy;
     int x, y;
    begin
        ox = rand[6];
        oy = rand[6];

        ox %= DISPLAY_WIDTH;
        oy %= DISPLAY_HEIGHT;

        for (fy = 0; fy < DISPLAY_HEIGHT; fy++) do
            for (fx = 0; fx < DISPLAY_WIDTH; fx++) do
                x = (fx + ox) % DISPLAY_WIDTH;
                y = (fy + oy) % DISPLAY_HEIGHT;

                if (display[x, y] == CHR_UNSET) then
                    if (y > 1 && ((x) % 2 != 0 || (y - 1) % 2 != 0)) then
                        if (display[x, y - 1] == CHR_WALL && display[x, y - 2] == CHR_FLOOR) then
                            display[x, y - 1] = CHR_FLOOR;
                            Kill(x, y - 1);
                            return;
                        end
                    end

                    if (x > 1 && ((x - 1) % 2 != 0 || (y) % 2 != 0)) then
                        if (display[x - 1, y] == CHR_WALL && display[x - 2, y] == CHR_FLOOR) then
                            display[x - 1, y] = CHR_FLOOR;
                            Kill(x - 1, y);
                            return;
                        end
                    end

                    if (y < DISPLAY_HEIGHT - 2 && ((x) % 2 != 0 || (y + 1) % 2 != 0)) then
                        if (display[x, y + 1] == CHR_WALL && display[x, y + 2] == CHR_FLOOR) then
                            display[x, y + 1] = CHR_FLOOR;
                            Kill(x, y + 1);
                            return;
                        end
                    end

                    if (x < DISPLAY_WIDTH - 2 && ((x + 1) % 2 != 0 || (y) % 2 != 0)) then
                        if (display[x + 1, y] == CHR_WALL && display[x + 2, y] == CHR_FLOOR) then
                            display[x + 1, y] = CHR_FLOOR;
                            Kill(x + 1, y);
                            return;
                        end
                    end
                end
            end
        end
    end

    bool Solve(int x, int y, int tx, int ty)
    var 
        bool top, left, bot, right;
    begin
            top   = display[x + 0, y - 1] == CHR_FLOOR;
            left  = display[x - 1, y + 0] == CHR_FLOOR;
            bot   = display[x + 0, y + 1] == CHR_FLOOR;
            right = display[x + 1, y + 0] == CHR_FLOOR;

            display[x, y] = CHR_PATH;

            if (x == tx && y == ty) then
                return true;
            end

            if (top) then
                if (Solve(x, y - 1, tx, ty)) then
                    return true;
                end
            end

            if (left) then
                if (Solve(x - 1, y, tx, ty)) then
                    return true;
                end
            end

            if (bot) then
                if (Solve(x, y + 1, tx, ty)) then
                    return true;
                end
            end

            if (right) then
                if (Solve(x + 1, y, tx, ty)) then
                    return true;
                end
            end

            display[x, y] = CHR_FLOOR;

            return false;
    end

end

Note: This and other examples are included in the BefunGen download

Square It

An implementation of the game Square It. Complete with a computer opponent.

program Square_It : display[34, 36] // 1 + 1+2*16 || 1 + 1+2*16 + 2
    const
        int FIELD_WIDTH := 16;
        int FIELD_HEIGHT := 16;

        char CHAR_VERTICAL := '|';
        char CHAR_HORIZONTAL := '-';
        char CHAR_EMPTY := ' ';
        char CHAR_JUNCTION := '+';
        char CHAR_EMPTYFIELD := ' ';
        char CHAR_PLAYER_P1 := 'X';
        char CHAR_PLAYER_P2 := 'O';
        char CHAR_PLAYER_NEUTRAL := '#';

    global
        char currPlayer;
        int p1_c, p2_c;
    begin
        restart();
    end

    void restart()
    var
        int choice;
    begin
        for(;;) do
            Init();

            outf    "WHAT DO YOU WANT TO PLAY?", 
                    "\r\n", 
                    "0: Player vs Player", 
                    "\r\n", 
                    "1: Player vs Computer", 
                    "\r\n", 
                    "2: Computer vs Computer",
                    "\r\n",
                    "\r\n",
                    "\r\n";

            in choice;

            if (choice == 0) then
                Game_P_v_P();
            elsif (choice == 1) then
                Game_P_v_NP();
            elsif (choice == 2) then
                Game_NP_v_NP();
            end
        end
    end

    void Game_P_v_P()
    var
        char winner;
    begin
        currPlayer = CHAR_PLAYER_P1;

        repeat
            outf "PLAYER ", currPlayer, ":\r\n";
            DoPlayerTurn();
        until (GameFinished())

        winner = GetWinningPlayer();

        if (winner == CHAR_PLAYER_P1) then
            out ">> PLAYER 1 (X) WINS !\r\n\r\n";
        elsif (winner == CHAR_PLAYER_P2) then
            out ">> PLAYER 2 (O) WINS !\r\n\r\n";
        else
            out ">> DRAW !\r\n\r\n";
        end

        return;
    end

    void Game_P_v_NP()
    var
        char winner;
    begin
        currPlayer = CHAR_PLAYER_P1;

        repeat
            if (currPlayer == CHAR_PLAYER_P1) then
                outf "PLAYER ", currPlayer, ":\r\n";
                DoPlayerTurn();
            else
                outf "COMPUTER ", currPlayer, ":\r\n";
                DoComputerTurn();
            end
        until (GameFinished())

        winner = GetWinningPlayer();

        if (winner == CHAR_PLAYER_P1) then
            out ">> YOU WIN !\r\n\r\n";
        elsif (winner == CHAR_PLAYER_P2) then
            out ">> YOU LOOSE !\r\n\r\n";
        else
            out ">> DRAW !\r\n\r\n";
        end

        return;
    end

    void Game_NP_v_NP()
    var
        char winner;
    begin
        currPlayer = CHAR_PLAYER_P1;

        repeat
            outf "COMPUTER ", currPlayer, ":\r\n";
            DoComputerTurn();
        until (GameFinished())

        winner = GetWinningPlayer();

        if (winner == CHAR_PLAYER_P1) then
            out ">> PC1 (X) WINS !\r\n\r\n";
        elsif (winner == CHAR_PLAYER_P2) then
            out ">> PC2 (O) WINS !\r\n\r\n";
        else
            out ">> DRAW !\r\n\r\n";
        end

        return;
    end

    void Init()
    var
        int x, y;
        int px, py;
    begin
        for(x = 0; x < FIELD_WIDTH; x++) do
            if (x > 9) then
                display[2 + x*2, 0] = (char)(x + (int)'7');
            else
                display[2 + x*2, 0] = (char)(x + (int)'0');
            end
        end

        for(y = 0; y < FIELD_HEIGHT; y++) do
            if (y > 9) then
                display[0, 2 + y*2] = (char)(y + (int)'7');
            else
                display[0, 2 + y*2] = (char)(y + (int)'0');
            end
        end

        for(x = 0; x < FIELD_WIDTH; x++) do
            for(y = 0; y < FIELD_HEIGHT; y++) do
                px = 2 + x*2;
                py = 2 + y*2;

                // CENTER
                display[px + 0, py + 0] = CHAR_EMPTYFIELD; 

                // TOP RIGHT
                display[px + 1, py + 1] = CHAR_JUNCTION;

                // BOTTOM RIGHT
                display[px - 1, py + 1] = CHAR_JUNCTION;

                // BOTTOM LEFT
                display[px - 1, py - 1] = CHAR_JUNCTION;

                // TOP LEFT
                display[px + 1, py - 1] = CHAR_JUNCTION; 

                // TOP
                if (y == 0) then
                    display[px + 0, py - 1] = CHAR_HORIZONTAL; 
                else
                    display[px + 0, py - 1] = CHAR_EMPTY; 
                end

                // RIGHT
                if (x == FIELD_WIDTH - 1) then
                    display[px + 1, py + 0] = CHAR_VERTICAL; 
                else
                    display[px + 1, py + 0] = CHAR_EMPTY; 
                end

                // BOTTOM
                if (y == FIELD_HEIGHT - 1) then
                    display[px + 0, py + 1] = CHAR_HORIZONTAL;
                else
                    display[px + 0, py + 1] = CHAR_EMPTY; 
                end

                // LEFT
                if (x == 0) then
                    display[px - 1, py + 0] = CHAR_VERTICAL;
                else
                    display[px - 1, py + 0] = CHAR_EMPTY;
                end
            end
        end
    end

    void DoPlayerTurn()
    var
        char x,y,d;

        int ix, iy, idx, idy;

        int posx, posy;
    begin
        out "    ";
        out "X: ";
        in x;
        out x;
        out " Y: ";
        in y;
        out y;
        out " Direction (U/D/L/R): ";
        in d;
        outf d, "\r\n";

        if (x >= '0' && x <= '9') then
            ix = (int)x - (int)'0';
        elsif (x >= 'A' && x <= 'Z') then
            ix = (int)x - (int)'A';
        elsif (x >= 'a' && x <= 'z') then
            ix = (int)x - (int)'a';
        else
            out "    ";
            out "ERROR - CANT PARSE INPUT (X)\r\n";
            DoPlayerTurn();
            return;
        end

        if (y >= '0' && y <= '9') then
            iy = (int)y - (int)'0';
        elsif (y >= 'A' && y <= 'Z') then
            iy = (int)y - (int)'A';
        elsif (y >= 'a' && y <= 'z') then
            iy = (int)y - (int)'a';
        else
            out "ERROR - CANT PARSE INPUT (Y)\r\n";
            DoPlayerTurn();
            return;
        end

        if (d == 'U' || d == 'u') then
            idx = 0;
            idy = -1;
        elsif (d == 'R' || d == 'r') then
            idx = 1;
            idy = 0;
        elsif (d == 'D' || d == 'd') then
            idx = 0;
            idy = 1;
        elsif (d == 'L' || d == 'l') then
            idx = -1;
            idy = 0;
        else
            out "    ";
            out "ERROR - CANT PARSE INPUT (DIRECTION)\r\n";
            DoPlayerTurn();
            return;
        end

        posx = 2 + ix*2 + idx;
        posy = 2 + iy*2 + idy;

        if (display[posx, posy] == CHAR_EMPTY) then
            DoTurn(ix, iy, idx, idy);

            return;
        else
            out "    ";
            out "ERROR - FIELD ALREADY SET\r\n";
            DoPlayerTurn();
            return;
        end
    end

    void DoTurn(int x, int y, int dx, int dy)
    var
        int posx, posy;

        bool t_a, t_b;
    begin
        posx = 2 + 2*x;
        posy = 2 + 2*y;

        if (dx == 0) then
            display[posx + dx, posy + dy] = CHAR_HORIZONTAL;
        else
            display[posx + dx, posy + dy] = CHAR_VERTICAL;
        end

        t_a = testField(x, y);
        t_b = testField(x + dx, y + dy);

        if (! (t_a || t_b)) then
            SwitchPlayer();
        end
    end

    void DoComputerTurn()
    begin
        if (FindComputerTurn(3)) then 
            return;
        end

        if (FindComputerTurn(1)) then 
            return;
        end

        if (FindComputerTurn(0)) then 
            return;
        end

        if (FindComputerTurn(2)) then 
            return;
        end

        while (true) do out "ERROR"; end
    end

    bool FindComputerTurn(int target_surr)
    var 
        int c_x, c_y;
        int x, y;
        int r_x, r_y, r_d;

        int c_i, i;
        int dx, dy;
    begin
        r_x = RAND[4];
        r_y = RAND[4];
        r_d = RAND[1];

        for(c_x = 0; c_x < FIELD_WIDTH; c_x++) do
            for(c_y = 0; c_y < FIELD_HEIGHT; c_y++) do
                x = (c_x + r_x) % FIELD_WIDTH;
                y = (c_y + r_y) % FIELD_HEIGHT;

                if (getSurrounding(x, y) == target_surr) then
                    for(c_i = 0; c_i < 4; c_i++) do
                        i = (c_i + r_d) % 4;

                        switch(i)
                        begin
                            case 0:
                                dx = 0;
                                dy = -1;
                            end 
                            case 1:
                                dx = 0;
                                dy = 1;
                            end 
                            case 2:
                                dx = -1;
                                dy = 0;
                            end 
                            case 3:
                                dx = 1;
                                dy = 0;
                            end 
                        end

                        if (display[2+2*x + dx, 2+2*y + dy] == CHAR_EMPTY) then
                            switch(i)
                            begin
                                case 0:
                                    outf "  X: ", x, " Y: ", y, " D: [UP]", "\r\n";
                                end 
                                case 1:
                                    outf "  X: ", x, " Y: ", y, " D: [DOWN]", "\r\n";
                                end 
                                case 2:
                                    outf "  X: ", x, " Y: ", y, " D: [LEFT]", "\r\n";
                                end 
                                case 3:
                                    outf "  X: ", x, " Y: ", y, " D: [RIGHT]", "\r\n";
                                end 
                            end

                            DoTurn(x, y, dx, dy);

                            return true;
                        end
                    end
                end
            end
        end

        return false;
    end

    bool TestField(int x, int y)
    var
        bool result;
    begin
        x = 2 + x*2;
        y = 2 + y*2;

        result = true;

        result &= (display[x, y] == CHAR_EMPTYFIELD);

        result &= (display[x + 1, y] != CHAR_EMPTY);
        result &= (display[x - 1, y] != CHAR_EMPTY);
        result &= (display[x, y + 1] != CHAR_EMPTY);
        result &= (display[x, y - 1] != CHAR_EMPTY);

        if (result) then
            display[x, y] = currplayer;
            return true;
        else
            return false;
        end
    end

    void SwitchPlayer() 
    begin
        if (currplayer == CHAR_PLAYER_P1) then
            currplayer = CHAR_PLAYER_P2;
        else
            currplayer = CHAR_PLAYER_P1;
        end

        display[DISPLAY_WIDTH - 9, DISPLAY_HEIGHT - 1] = 'P';
        display[DISPLAY_WIDTH - 8, DISPLAY_HEIGHT - 1] = 'L';
        display[DISPLAY_WIDTH - 7, DISPLAY_HEIGHT - 1] = 'A';
        display[DISPLAY_WIDTH - 6, DISPLAY_HEIGHT - 1] = 'Y';
        display[DISPLAY_WIDTH - 5, DISPLAY_HEIGHT - 1] = 'E';
        display[DISPLAY_WIDTH - 4, DISPLAY_HEIGHT - 1] = 'R';
        display[DISPLAY_WIDTH - 3, DISPLAY_HEIGHT - 1] = ' ';
        display[DISPLAY_WIDTH - 2, DISPLAY_HEIGHT - 1] = currplayer;

        display[1, DISPLAY_HEIGHT - 1] = (char)((p1_c/100)%10 + 48);
        display[2, DISPLAY_HEIGHT - 1] = (char)((p1_c/10)%10 + 48);
        display[3, DISPLAY_HEIGHT - 1] = (char)((p1_c/1)%10 + 48);
        display[4, DISPLAY_HEIGHT - 1] = ' ';
        display[5, DISPLAY_HEIGHT - 1] = '-';
        display[6, DISPLAY_HEIGHT - 1] = ' ';
        display[7, DISPLAY_HEIGHT - 1] = (char)((p2_c/100)%10 + 48);
        display[8, DISPLAY_HEIGHT - 1] = (char)((p2_c/10)%10 + 48);
        display[9, DISPLAY_HEIGHT - 1] = (char)((p2_c/1)%10 + 48);
    end

    int GetSurrounding(int x, int y)
    var
        int result;
    begin
        result = 0;

        x = 2 + x*2;
        y = 2 + y*2;

        result += (int)(display[x + 1, y] != CHAR_EMPTY);
        result += (int)(display[x - 1, y] != CHAR_EMPTY);
        result += (int)(display[x, y + 1] != CHAR_EMPTY);
        result += (int)(display[x, y - 1] != CHAR_EMPTY);

        return result;
    end

    bool GameFinished()
    var
        int x, y;
    begin
        p1_c = 0;
        p2_c = 0;

        for(x = 0; x < FIELD_WIDTH; x++) do
            for(y = 0; y < FIELD_HEIGHT; y++) do
                if (display[2+2*x, 2+2*y] == CHAR_PLAYER_P1) then
                    p1_c++;
                elsif (display[2+2*x, 2+2*y] == CHAR_PLAYER_P2) then
                    p2_c++;
                end
            end
        end

        return p1_c + p2_c == FIELD_WIDTH * FIELD_HEIGHT;
    end

    char GetWinningPlayer()
    begin
        if (p1_c > p2_c) then
            return CHAR_PLAYER_P1;
        elsif (p1_c < p2_c) then
            return CHAR_PLAYER_P2;
        else
            return CHAR_PLAYER_NEUTRAL;
        end
    end

Note: This and other examples are included in the BefunGen download