Updated BefunGen to >> BefunUtils
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
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.
|
||||
|
||||
##Additional
|
||||
|
||||
###Capture GIF
|
||||
|
||||

|
||||
|
||||
With the menu point "Capture GIF" you can create an animated .gif animation of your running program.
|
||||
You can set the amount of steps to capture and the animation delay between the steps. You can also set the final delay before the animation restarts.
|
||||
There is also the "Automatic frame count" option, only use this if your program terminates in a reasonable amount of frames.
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 49 KiB |
BIN
www/data/programs/desc/BefunUtils/01_Manuals/BefunExec_Main.png
Normal file
BIN
www/data/programs/desc/BefunUtils/01_Manuals/BefunExec_Main.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 41 KiB |
@@ -0,0 +1,52 @@
|
||||
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**
|
||||
BIN
www/data/programs/desc/BefunUtils/01_Manuals/BefunRep_Main.png
Normal file
BIN
www/data/programs/desc/BefunUtils/01_Manuals/BefunRep_Main.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 47 KiB |
@@ -0,0 +1,81 @@
|
||||
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
|
||||
|
||||

|
||||
|
||||
> **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.
|
||||
BIN
www/data/programs/desc/BefunUtils/01_Manuals/BefunWrite_Main.png
Normal file
BIN
www/data/programs/desc/BefunUtils/01_Manuals/BefunWrite_Main.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
@@ -0,0 +1,478 @@
|
||||
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`
|
||||
|
||||
```textfunge
|
||||
program example_01 : display[0, 0]
|
||||
begin
|
||||
// code
|
||||
end
|
||||
|
||||
void method()
|
||||
begin
|
||||
// code
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
between program` and `end` 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
|
||||
|
||||
```textfunge
|
||||
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:
|
||||
|
||||
```textfunge
|
||||
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
|
||||
|
||||
```textfunge
|
||||
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:
|
||||
|
||||
```textfunge
|
||||
var_1[0] = var_2[4 + 1];
|
||||
```
|
||||
|
||||
###Constants
|
||||
|
||||
At the same position as global variables can (global) constants be defined:
|
||||
|
||||
```textfunge
|
||||
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:
|
||||
|
||||
```textfunge
|
||||
0
|
||||
9283
|
||||
-9283
|
||||
```
|
||||
|
||||
And also Base-16 (Hexadecimal) integer literals with `0x`
|
||||
|
||||
```textfunge
|
||||
0x00
|
||||
0xF0F
|
||||
0x123
|
||||
```
|
||||
|
||||
Digit literals have a `#` prefix:
|
||||
|
||||
```textfunge
|
||||
#0
|
||||
#6
|
||||
#9
|
||||
```
|
||||
|
||||
Char literals are surrounded by single ticks:
|
||||
|
||||
```textfunge
|
||||
' '
|
||||
'A'
|
||||
'a'
|
||||
```
|
||||
|
||||
Boolean literals consist of the two boolean keywords:
|
||||
|
||||
```textfunge
|
||||
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)
|
||||
|
||||
```textfunge
|
||||
""
|
||||
"hello"
|
||||
"hello \r\n second line"
|
||||
```
|
||||
|
||||
And Array literals are the values inside of a set of curly braces:
|
||||
|
||||
```textfunge
|
||||
{0, 1}
|
||||
{'h', 'e', 'l', 'l', 'o'}
|
||||
{true, false, true}
|
||||
```
|
||||
|
||||
###Methods
|
||||
|
||||
Methods consist of 2 parts, the header and the body:
|
||||
|
||||
```textfunge
|
||||
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
|
||||
|
||||
```textfunge
|
||||
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
|
||||
|
||||
```textfunge
|
||||
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
|
||||
|
||||
```textfunge
|
||||
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
|
||||
|
||||
```textfunge
|
||||
// (init ; cond ; stmt)
|
||||
for (i = 0; i < 10; i++ ) do
|
||||
// Code
|
||||
end
|
||||
```
|
||||
|
||||
Each field can also be empty, allowing for this simple, infinite loop:
|
||||
|
||||
```textfunge
|
||||
for (;;) do
|
||||
// Code
|
||||
end
|
||||
// <-- unreachable (without goto)
|
||||
```
|
||||
|
||||
#### Switch case
|
||||
|
||||
If you want to distinct multiple values you can use a switch statement:
|
||||
|
||||
```textfunge
|
||||
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
|
||||
|
||||
```textfunge
|
||||
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
|
||||
|
||||
```textfunge
|
||||
a = ((5 + 5)*4 - 10)/-1 % 4;
|
||||
```
|
||||
|
||||
####Boolean operators
|
||||
|
||||
You can use the boolean operators `&&` (AND), `||` (OR), `^` (XOR), `!` (NOT).
|
||||
|
||||
```textfunge
|
||||
a = (10 == x) ^ true;
|
||||
b = !(10 == x);
|
||||
```
|
||||
|
||||
####Comparison
|
||||
|
||||
You can use the normal c-like comparison operators `==`, `!=`, `<`, `>`, `<=` and `>=`
|
||||
|
||||
```textfunge
|
||||
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.
|
||||
|
||||
```textfunge
|
||||
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.
|
||||
|
||||
```textfunge
|
||||
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.
|
||||
|
||||
```textfunge
|
||||
// Code
|
||||
begin
|
||||
// Code
|
||||
// Code
|
||||
end
|
||||
// Code
|
||||
```
|
||||
|
||||
####De-/Increment
|
||||
|
||||
With `++` and `--` you can increment/decrement a variable in a shorter way than a assignment.
|
||||
|
||||
```textfunge
|
||||
a++;
|
||||
a = a + 1; // equally
|
||||
```
|
||||
|
||||
####Assignments
|
||||
|
||||
With a single `=` you can assign a value to a variable.
|
||||
|
||||
```textfunge
|
||||
a = 3;
|
||||
b[3] = 0;
|
||||
```
|
||||
|
||||
###Method calls
|
||||
|
||||
Method calls are pretty much like in every other language.
|
||||
|
||||
```textfunge
|
||||
method_1(0, 6, "hello");
|
||||
method_2(getA(), getB(0));
|
||||
```
|
||||
|
||||
###Comments
|
||||
|
||||
You can write either full line comments with `//` or block comments with `/*` and `*/`
|
||||
|
||||
```textfunge
|
||||
/* 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.
|
||||
|
||||
```textfunge
|
||||
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:
|
||||
|
||||
```textfunge
|
||||
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
|
||||
|
||||
```textfunge
|
||||
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
|
||||
```
|
||||
@@ -0,0 +1,37 @@
|
||||
In TextFunge you can optionally define a read- and writable display area.
|
||||
|
||||
```textfunge
|
||||
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.
|
||||
|
||||
```textfunge
|
||||
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:
|
||||
|
||||
```textfunge
|
||||
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.
|
||||
@@ -0,0 +1,37 @@
|
||||
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](/programs/view/BefunGen) 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](/programs/view/BefunGen) 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](/programs/view/BefunGen), as you probably can assume, has no "real" size limit to it.
|
||||
@@ -0,0 +1,29 @@
|
||||
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.
|
||||
@@ -0,0 +1,14 @@
|
||||
###Hello World
|
||||
|
||||
A simple "Hello World"
|
||||
|
||||
```textfunge
|
||||
program example
|
||||
begin
|
||||
out "Hello World\r\n";
|
||||
quit;
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
> **Note:** *This and other examples are included in the BefunGen download*
|
||||
@@ -0,0 +1,77 @@
|
||||
###Sieve of Erasthothenes
|
||||
|
||||
Calculates the primes between 0 and 19200 with the sieve of Erasthothenes
|
||||
|
||||
```textfunge
|
||||
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*
|
||||
@@ -0,0 +1,43 @@
|
||||
###The Euclidean algorithm
|
||||
|
||||
A simple, *recursive* implementation of the [euclidian algorithm](http://en.wikipedia.org/wiki/Euclidean_algorithm)
|
||||
|
||||
```textfunge
|
||||
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*
|
||||
@@ -0,0 +1,38 @@
|
||||
###Fibonacci numbers
|
||||
|
||||
Calculates the [Fibonacci sequence](http://en.wikipedia.org/wiki/Fibonacci_number)
|
||||
|
||||
```textfunge
|
||||
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*
|
||||
@@ -0,0 +1,37 @@
|
||||
###Fizz Buzz
|
||||
|
||||
A simple implementation of the [Fizz Buzz](http://en.wikipedia.org/wiki/Fizz_buzz) game.
|
||||
|
||||
```textfunge
|
||||
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*
|
||||
@@ -0,0 +1,107 @@
|
||||
###PI Calculation
|
||||
|
||||
Calculates PI to a certain degree with the Monte Carlo algorithm
|
||||
|
||||
```textfunge
|
||||
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*
|
||||
@@ -0,0 +1,285 @@
|
||||
###Befunge-93 interpreter
|
||||
|
||||
An Befunge-93 interpreter
|
||||
|
||||
```textfunge
|
||||
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*
|
||||
@@ -0,0 +1,224 @@
|
||||
###Sudoku Generator
|
||||
|
||||
Generates a random (but valid) Sudoku puzzle
|
||||
|
||||
```textfunge
|
||||
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*
|
||||
@@ -0,0 +1,101 @@
|
||||
###Conway's Game of Life
|
||||
|
||||
A simulation of [Conway's Game of Life](http://en.wikipedia.org/wiki/Conway%27s_Game_of_Life)
|
||||
|
||||
```textfunge
|
||||
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*
|
||||
@@ -0,0 +1,252 @@
|
||||
###Maze Generator
|
||||
|
||||
Generates a Maze on the display with the [Hunt&Kill algorithm](http://weblog.jamisbuck.org/2011/1/24/maze-generation-hunt-and-kill-algorithm) - thens solves is by recursively trying every path
|
||||
|
||||
```textfunge
|
||||
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*
|
||||
@@ -0,0 +1,500 @@
|
||||
###Square It
|
||||
|
||||
An implementation of the game [Square It](http://en.wikipedia.org/wiki/Dots_and_Boxes). Complete with a computer opponent.
|
||||
|
||||
```textfunge
|
||||
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*
|
||||
133
www/data/programs/desc/BefunUtils/index.markdown
Normal file
133
www/data/programs/desc/BefunUtils/index.markdown
Normal file
@@ -0,0 +1,133 @@
|
||||
This is my collection of tools and libraries for the esoteric programming language [Befunge](http://esolangs.org/wiki/Befunge).
|
||||
|
||||
IT consists of the following components:
|
||||
|
||||
###[BefunGen](https://github.com/Mikescher/BefunGen):
|
||||
A library to automatically generate Befunge-93 programs out of a imperative-programming-language
|
||||
###[BefunGenTest](https://github.com/Mikescher/BefunGenTest):
|
||||
A test set for BefunGen
|
||||
###[BefunWrite](https://github.com/Mikescher/BefunWrite):
|
||||
A samll editor for Textfunge, the language used by BefunGen - use this if you want to try BefunGen for yourself
|
||||
###[BefunHighlight](https://github.com/Mikescher/BefunHighlight):
|
||||
A dynamic Befunge-93 syntax highlighting library. Highlights your sourcecode intelligent and context-sensitive
|
||||
###[BefunExec](https://github.com/Mikescher/BefunExec):
|
||||
A (fast) Befunge-93 interpreter and debugger
|
||||
###[BefunRep](https://github.com/Mikescher/BefunRep):
|
||||
A tool to calculate (the best) number-representation in Befunge-93 space
|
||||
|
||||
|
||||
|
||||
> **NOTE:**
|
||||
>
|
||||
> If you don't know the esoteric language Befunge I can refer you to the [esolang page](http://esolangs.org/wiki/Befunge) and my own [tutorial](/blog/2/Lets_do_Befunge93)
|
||||
|
||||
## BefunWrite
|
||||
|
||||
BefunWrite is the main program that uses all the other parts.
|
||||
It's an IDE in which you can write a program in *TextFunge*, and compile it to valid Befunge-98 code.
|
||||
|
||||
> **NOTE:**
|
||||
>
|
||||
> While the generated Code practically is Befunge-98, you can use it in nearly every Befunge-93 interpreter.
|
||||
> Because it doesn't use a single command, which was not defined in Befunge-93, the only non-Befunge-93 feature is the extended file size.
|
||||
> Because this tool can generate fairly big Befunge-93 code, it often exceeds the size of 80x25, and is so no longer totally valid Befunge-93 code.
|
||||
> But for the sake of confusion I will refer in the rest of these documents to it as Befunge-93 code.
|
||||
|
||||
In BefunWrite you write your source code in the, specially for this developed, language **TextFunge**.
|
||||
BefunWrite supports you in this process with a lot of the basic IDE features you already know from other IDE's.
|
||||
After written you can compile your TextFunge code into BEfunge-93 code and execute it in **BefunExec**.
|
||||
|
||||
The main advantage for you is how you can easily generate even complex programs in Befunge.
|
||||
Because TextFunge supports all the basic features of a procedural language you can use constructs like:
|
||||
|
||||
- if-clauses and switch-cases
|
||||
- for-loops, while-loops, repeat-until-loops
|
||||
- methods
|
||||
- recursion
|
||||
- global and local variables with different data-types
|
||||
- GOTO's
|
||||
- arithmetical and logical expressions
|
||||
|
||||
BefunWrite also provides an easy interface for the multiple compiler-settings, for more information please visit the individual manuals.
|
||||
|
||||
## BefunGen
|
||||
|
||||
BefunGen is the core of this compilations. It's a compiler for for TextFunge and a code generator for Befunge.
|
||||
Essentially it performs the conversion between TextFunge and Befunge. Most of the generated Befunge programs could be a lot smaller if an actual person would take the time writing them.
|
||||
That is the case because the generated Befunge code has a lot of organisation code included. It needs to manage the global variables and also the local ones. The local variables need initialization and in case of a different method call their current state needs to be saved. Also there has to be a call-stack to return to previous methods and re-initialization code when you jump back into methods.
|
||||
|
||||
This is important to understand, while I always try to optimize the generated code as much as I can it will always be a good amount bigger (and slower) than actual human-made code. This is also the case because there are neat little "tricks" and design concepts in Befunge that you just can't express in a procedural language.
|
||||
|
||||
But thats not really the problem, because the target of BefunGen is **not** generate code that could also be made by hand. The target code size is code so big that it would be totally impractical to write by hand (without spending days and weeks on it).
|
||||
|
||||
BefunGen itself is not a standalone program, but a simple library. You are free to use the DLL in your own program (but beware of the license, please give me credits...). If you need help how to use it you can either simply look at the source code (of BefunGen or BefunWrite) or write me a friendly mail.
|
||||
|
||||
## BefunExec
|
||||
|
||||
BefunExec is a fast Befunge-93 interpreter (without any program-size limitations) and a simple tool to execute and debug the generated Befunge-93 files.
|
||||
|
||||
While developing BefunGen I encountered the problem that not many interpreters where able to execute my programs.
|
||||
Because of the properties of my generated code I needed an interpreter that was
|
||||
|
||||
- really fast, it needed to execute really many executions per second
|
||||
- able to open and display large to *extremely* large programs
|
||||
- able too zoom in programs (because they can be large)
|
||||
- able to debug the program (show stack, output, input, breakpoints, single-step ...)
|
||||
|
||||
As you can imagine, I didn't find an interpreter that fitted my needs and so I wrote my own.
|
||||
The big point that makes BefunExec unique is it's very high speed. On my machine (and its not really a good one) I reach a maximum speed of **6.5 MHz**. This are over **6 million** executions per second, enough for most of my programs :D.
|
||||
|
||||
Some other features are (as stated above) the ability to set breakpoints, step slowly through the program and zoom into specific parts.
|
||||
Also you are able to capture the program execution as a gif animation.
|
||||
One other big feature is the integration of BefunHighlight, which will be explained in the BefunHighlight section below.
|
||||
|
||||
## BefunHighlight
|
||||
|
||||
BefunHighlight is just a helper library mainly for BefunExec.
|
||||
BefunExec has normal Befunge syntax-highlighting implemented, that means that every character is colored based on its function.
|
||||
The problem here is that there may be code that never gets executed (not part of the real program), or there may be code that only gets used inside of string-mode (so the function doesn't matter, only the ASCII value).
|
||||
|
||||
BefunHighlight tries to solve this by evaluating every possible path an program can execute and so calculating the ways a single command is used.
|
||||
Based on these informations it's now possible for another program to better highlight the source code.
|
||||
|
||||
Be aware that **p**ut and **g**et operations will invalidate the calculated values and it is needed to update them.
|
||||
|
||||
## BefunRep
|
||||
|
||||
A common problem with Befunge is the *(efficient)* representation of big numbers. *(= putting a number on the stack with the least amount of instructions)*
|
||||
|
||||
BefunRep is a commandline tool to generate a list of representations for all numbers in a specified range. I'm pretty sure the calculation of the optimal representation is a NP complete. But BefunRep tries to to find good representations for all numbers via various algorithms. And it does a pretty good job. It finds for all the numbers between -1 million and +1 million representations with a maximum of eleven characters.
|
||||
|
||||
Here an example call to BefunRep:
|
||||
|
||||
> **\> BefunRep.exe -lower=0 -upper=1000 -iterations=3 -stats=3 -q -safe="safe.bin" -out="out.csv" -reset**
|
||||
|
||||
This calculates the numbers from **0** to **1000**.
|
||||
With a maximum of **3** iterations *(use -1 to calculate until no more improvmenets can be found)*
|
||||
Safe the results in binary format in the file **safe.bin**
|
||||
If the safe already exists it will be reseted (-**reset**)
|
||||
And exports the results readable to **out.csv**
|
||||
|
||||
You can also update an existing safe
|
||||
|
||||
> **\> BefunRep.exe -safe="safe.bin" -iterations=-1**
|
||||
|
||||
Or don't calculate anything and only output an existing safe into another format
|
||||
|
||||
> **\> BefunRep.exe -safe="safe.bin" -iterations=0 -stats=3 -out="out.json"**
|
||||
|
||||
Here an example of a few calculated values:
|
||||
|
||||
Number | Representation
|
||||
-------|----------------
|
||||
113564 | `"tY!"**3/`
|
||||
113565 | `"qC-"**3/`
|
||||
113566 | `"[' "**2-`
|
||||
113567 | `"[' "**1-`
|
||||
113568 | `"[' "**`
|
||||
113569 | `"~~U"++:*`
|
||||
113570 | `"[' "**2+`
|
||||
113571 | `"wj"*5+9*`
|
||||
113572 | `"[' "**4+`
|
||||
113573 | `"[' "**5+`
|
||||
113574 | `"E~(&"*+*`
|
||||
Reference in New Issue
Block a user