Triforce
Triforce is a tape based esoteric programming language designed by Anthony Ma in 2013. Triforce is identical to brainfuck while purely using triangles, and with the addition of an operator that resets a memory cell to 0. Triforce files are stored with the extension .▲ The language and name is inspired by the Triforce of the Legend of Zelda series.
Overview
Triforce has a total of 14 operands:
| Command | Description |
|---|---|
▶
|
Move the pointer to the right |
◀
|
Move the pointer to the left |
▲
|
Increment the memory cell under the pointer |
▼
|
Decrement the memory cell under the pointer |
⧏
|
Output the character signified by the cell at the pointer |
⧐
|
Input a character and store it in the cell at the pointer |
⧎
|
Input and output a character at the same time |
[Space]
|
Reset the memory cell under the pointer to 0 |
◤
|
Jump past the matching ◥ if the cell under the pointer is 0
|
◥
|
Jump back to the matching ◤ if the cell under the pointer is nonzero
|
◢
|
Jump back to the first memory pointer |
◣
|
Jump past to the last memory pointer |
◮
|
Switch to integer mode |
◭
|
Switch to ASCII mode |
Switching to integer will just shift all input and output by 48.
Examples
Hello, World!
Here's the example brainfuck program with the program converted to Triforce:
brainfuck:
>+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.>>>++++++++[<++++>-] <.>>>++++++++++[<+++++++++>-]<---.<<<<.+++.------.--------.>>+.
Triforce:
▶▲▲▲▲▲▲▲▲▲◤◀▲▲▲▲▲▲▲▲▶▼◥◀⧏▶▲▲▲▲▲▲▲◤◀▲▲▲▲▶▼◥◀▲⧏▲▲▲▲▲▲▲⧏⧏▲▲▲⧏▶▶▶▲▲▲▲▲▲▲▲◤◀▲▲▲▲▶▼◥ ◀⧏▶▶▶▲▲▲▲▲▲▲▲▲▲◤◀▲▲▲▲▲▲▲▲▲▶▼◥◀▼▼▼⧏◀◀◀◀⧏▲▲▲⧏▼▼▼▼▼▼⧏▼▼▼▼▼▼▼▼⧏▶▶▲⧏
Implementation
The following is an interpreter of Triforce written in Java with a max pointer register length of 1024. The argument it takes in is the path to the Triforce script. A .jar of the following interpreter is available here.
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
public class Triforce {
public static void main(String[] args) {
try {
parse(readFile(args[0]));
} catch (IOException e) {
e.printStackTrace();
}
}
public static void parse(String stuff) {
final int toInt = '\u25ee';
final int toAscii = '\u25ed';
final char up = '\u25b2';
final char down = '\u25bc';
final char left = '\u25c0';
final char right = '\u25b6';
final char rightb = '\u25e3';
final char leftb = '\u25e2';
final char rightu = '\u25e5';
final char leftu = '\u25e4';
final char space = ' ';
final char nl = '\n';
final char in = '\u29d0';
final char out = '\u29cf';
final char inOut = '\u29ce';
boolean intOut = false;
int loopCount = 0;
int line = 1;
int[] count = new int[1024];
int reg = 0;
int nextChar;
char[] chars = stuff.toCharArray();
InputStreamReader converter = new InputStreamReader(System.in);
BufferedReader input = new BufferedReader(converter);
for (nextChar = 0; nextChar < chars.length; nextChar++) {
char c = chars[nextChar];
switch (c) {
case toInt:
intOut = true;
break;
case toAscii:
intOut = false;
break;
case up:
count[reg]++;
break;
case down:
count[reg]--;
break;
case rightb:
reg = 0;
break;
case leftb:
reg = 1023;
break;
case rightu:
if (count[reg] != 0) {
for (nextChar = nextChar; nextChar > 0; nextChar--) {
if (chars[nextChar] == leftu) {
break;
}
}
}
else {
loopCount--;
if (loopCount != 0) {
System.out.println("line " + line + ": possible unopened " + leftu);
}
}
break;
case leftu:
if (count[reg] == 0) {
for (nextChar = nextChar; nextChar < chars.length; nextChar++) {
if (chars[nextChar] == rightu) {
break;
}
}
}
else {
if (loopCount != 0) {
System.out.println("line " + line + ": possible unclosed " + rightu);
}
loopCount++;
}
break;
case right:
if (reg < 1023)
reg++;
else
System.out.println("line " + line + ": max register reached(" + reg + ")");
break;
case left:
if (reg > 0)
reg--;
else
System.out.println("line " + line + ": min register reached(" + reg + ")");
break;
case space:
count[reg] = 0;
break;
case nl:
if (loopCount == 0) {
line++;
}
break;
case out:
if (intOut)
System.out.print(count[reg]);
else
System.out.print((char)count[reg]);
break;
case in:
try {
if (intOut)
count[reg] = (char)input.read() - 48;
else
count[reg] = (char)input.read();
} catch (IOException e) {
e.printStackTrace();
}
break;
case inOut:
try {
if (intOut)
count[reg] = (char)input.read() - 48;
else
count[reg] = (char)input.read();
} catch (IOException e) {
e.printStackTrace();
}
if (intOut)
System.out.print(count[reg]);
else
System.out.print((char)count[reg]);
break;
default:
System.out.println("line " + line + ": unexpected char '" + c + "'");
break;
}
}
try {
converter.close();
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private static String readFile(String path) throws IOException {
FileInputStream stream = new FileInputStream(new File(path));
try {
FileChannel fc = stream.getChannel();
MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
return Charset.defaultCharset().decode(bb).toString();
}
finally {
stream.close();
}
}
}