Undyne Programming Language
Undyne Programming Language (UPL) is a programming language designed to resemble a battle against Undyne in the game Undertale. It shares similarities with Brainfuck but differs in its execution and syntax.
UPL uses an array (memory) with a minimum length of 64. Each value in this array is an unsigned 32-bit integer. When the program starts, all values are set to 0.
A UPL program is divided into two files: Head and Quiver. The Head file contains the definition of the operations (referred to as arrows), and the Quiver file defines how to use the arrows. There can be a maximum of 1000 arrows defined at any given time, ranging from 000 to 999. Arrow 000 is the default arrow; its usage is possible but not recommended as it can be confusing in an already complex program.
The program works by launching arrows at the player. The player has a shield and needs to defend themselves. The arrows are executed when they touch the shield, but if the player is hurt, the program is terminated.
UPL was created in April 2025 by Joachim Rey
Arrows creation
Arrows are defined in the Head file. The general syntax of an arrow is:
[ARROW ID:OPERATION ADDITIONAL INFO]
There are seven types of definable arrows.
+ and -
+ and - arrows are defined using the following syntax :
[ARROW ID:+AMOUNT] [ARROW ID:+AMOUNT]
Examples:
[001:+89754] [002:-1]
> and <
> and < arrows are defined using the following syntax :
[ARROW ID:>AMOUNT] [ARROW ID:<AMOUNT]
Examples:
[001:>89754] [002:<1]
If the amount is out of the range of the memory, the pointer is placed at the end or at the start of the memory.
I and O
I (Input) and O (Output) arrows are defined using the following syntax :
[ARROW ID:I(0)] OR [ARROW ID:I(1)] [ARROW ID:O(0)] OR [ARROW ID:O(1)]
Parentheses stand for the parameter of the I/O function. A parameter of 0 means the I/O is a character, and 1 stands for an integer.
i
i arrows are defined using the following syntax :
[ARROW ID:i(STOP)OPERATIONS] [ARROW ID:i(STOP)OPERATIONS]
i arrows are while/if operations. For example:
[001:i(16)[<:001]]
This defines an i arrow with ID 001 that will execute arrow 001 with effect < while the current cell is not 16. There can be an infinite number of operations.
Example of a Head file
[001:+126][002:+32][003:-1][004:O(0)][005:>1][006:<1][007:i(32)[<:004n][<:005n][ <:004u][<:006n][<:004n][<:010u][<:004n][<:009n][<:003u]][008:+119][009:<2][010:> 2]
This will create the ten following arrows:
- [001:+126] : An arrow with ID 001 and operation +126
- [002:+32] : An arrow with ID 002 and operation +32
- [003:-1] : An arrow with ID 003 and operation -1
- [004:O(0)] : An arrow with ID 004 and operation O (Output character)
- [005:>1] : An arrow with ID 005 and operation > (move pointer by 1 to the right)
- [006:<1] : An arrow with ID 006 and operation < (move pointer by 1 to the left)
- [007:i(32)[<:004n][<:005n][<:004u][<:006n][<:004n][<:010u][<:004n][<:009n][<:003u]] : An arrow with ID 007 and operation i(32) (while the current memory cell's value is not 32, call arrows [<:004n], [<:005n][<:004u], [<:006n], [<:004n], [<:010u], [<:004n], [<:009n] and [<:003u]).
- [008:+119] : An arrow with ID 008 and operation +119
- [009:<2] : An arrow with ID 009 and operation < (move pointer by 2 to the left)
- [010:>2] : An arrow with ID 009 and operation > (move pointer by 2 to the right)
Note that the order does not matter when creating arrows or assigning them IDs. For example:
[512:>5][001:i(0)[<:856n]][856:-1]
Is a correct Head file.
Program execution
The program is executed by calling the arrows defined in the Head file, as specified in the Quiver file. The general syntax for arrow calls is:
[EFFECT:ARROW ID SHOOTING SIDE]
The shooting side (side of the screen) can be u (up), d (down), l (left), and r (right). This information can be omitted, but if omitted, the arrow will be shot from a random side.
There are two effects:
- <, which stands for 'do the operation and then nothing'
- (, which means 'do the operation and then destroy the arrows in the opposite direction for ten iterations'
For instance:
[<:001][<:002][<:003]
will call arrows 001, 002, and 003. If they successfully touch the player's shield, their operation will be executed.
[(:001u][<:001l][<:001r][<:001r][<:002d][<:001u][<:001u][<:001l][<:001r][<:001r][<:001d][<:003d]
will execute 001u, do its operation, then delete arrow [<:002d] because it is in the opposite direction (down). It will not delete [<:003d] as it is out of the ten-arrow range.
The ( effect could be used for if-else statements.
Program end
The program ends when the player dies (touched by an arrow) or when there are no more arrows (empty quiver).
Display
The program displays on a 640 by 480 window, with a heart in the middle (player), a shield and a terminal like interface at the bottom (dialogue box). Arrows are shot from the four sides of the window as defined in the Quiver file. Arrow textures and sounds when touching the shield need to be defined in the Sounds & Arrows folders. An additional Dashs folder can be added for the ( effect. All these folders and files are compressed in a .upl file (zip file).
Here is the complete file hierarchy. Note that the Head and Quiver files are the only compulsory files. All other files are optional.
MyProgram.upl/ ├─ Arrows/ │ ├─ 000.png │ ├─ Dashs/ │ ├─ 000.png │ ├─ Sounds/ │ ├─ 000.ogg │ ├─ Quiver ├─ Head
000 files are the default texture, sound, and dash. You could only create 007.png in Arrows, 002.png in Dash, and 010.ogg in Sounds, and the program would still work fine, but all other arrows would not be displayed or have sound.
Example of a simple program
Head:
[001:+126][002:+32][003:-1][004:O(0)][005:>1][006:<1][007:i(32)[<:004n][<:005n][ <:004u][<:006n][<:004n][<:010u][<:004n][<:009n][<:003u]][008:+119][009:<2][010:> 2]
Quiver:
[<:001u][<:005u][<:008u][<:005u][<:002u][<:009u][<:007u]
Output:
~w~ }w} |w| {w{ zwz ywy xwx www vwv uwu twt sws rwr qwq pwp owo nwn mwm lwl kwk jwj iwi hwh gwg fwf ewe dwd cwc bwb awa `w` _w_ ^w^ ]w] \w\ [w[ ZwZ YwY XwX WwW VwV UwU TwT SwS RwR QwQ PwP OwO NwN MwM LwL KwK JwJ IwI HwH GwG FwF EwE DwD CwC BwB AwA @w@ ?w? >w> =w= <w< ;w; :w: 9w9 8w8 7w7 6w6 5w5 4w4 3w3 2w2 1w1 0w0 /w/ .w. -w- ,w, +w+ *w* )w) (w( 'w' &w& %w% $w$ #w# "w" !w!
The Head has already be explained in the Arrows creation section, but here is a pseudo-code translation of the Quiver.
Add 126 to current cell Move the pointer by one to the right add 119 to current cell Move the pointer by one to the right add 32 to current cell Move the pointer by two to the left While current cell value is not 32 do: Output character Move the pointer by one to the right Output character Move the pointer by one to the left Output character Move the pointer by two to the right Output character Move the pointer by two to the left Remove 1 from current cell