Triforce

From Esolang
Jump to navigation Jump to search

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();
		}
	}

}