Skip to content
A 2D Tac-It Language.
Lua Python
Branch: master
Clone or download
Latest commit 89bae7c Mar 22, 2017
Type Name Latest commit message Commit time
Failed to load latest commit information.
code.tac Fixed Path Bugs Mar 16, 2017
functions.lua Felt like I was cheating the language Mar 19, 2017
list.lua Added \s, List iterator and updated readme Mar 22, 2017
main.lua Forgot to actually include this Mar 22, 2017
otherhacks.lua Now Turing Complete! Mar 16, 2017
stringhacks.lua Added write and tostring Mar 17, 2017


A 2D Tac-It Language.


TacO is a strange approach to language design, combining a 2D Language with a Taccing one, the code runs as interconnected chains.

The firsts and most important character is the @. It designates where the program should "Start".

From here, the code repeatedly branches out, chaining together all the functions in adjecency, before eventually running it.


The above program is very simply, it just prints a 1. And as can be seen, the order of actions may be backwards to what many programmers are used to. Firstly, the IP starts at @, then it moves directly to the p, but doesn't do anything yet. Afterwards, it moves to the 1, which will act as p's arguments. Anything past the 1 would be one of 1's arguments. And so on.

Arguments do have an order, in particular, Left, Up, Right, then Down. When the IP reaches a branch, it will stretch out each of these paths in this order, and use each of these branches as arguments.


Prints 1 2 3

Branches can also intercect with eachother, but not themselves. Take the following example.


Now things have started getting a bit confusing, but just hold on tight.

This program prints 1 1

The # doesn't do anything, and that's intentional.

When the program gets to the p, there's a branching, but the program won't just do loops, instead, it cuts off if it's "explored" before. So the two branches look like the following to the program, when unwrapped.


Note that both the 1 and the trailing no-op are used by both program. So this might cause unexpected behaviour.


Positive Arithmatic, That is, +, *, ^ and so on, can generally be implemented by a combination of + and amounts of *.

Adding any amount of numbers is done through the + command. So 1+1 can be written as:


But because of how Branches work, you can also pipe together a bunch of arguments, like:

 1 1 1 1 1 1

Which would give 6.

The * command, runs the second branch the first input times. So:


Will print 6 1s, followed by newlines.

To multiply two numbers, we need a combination of + and *.


Gives 3 fives on the branch. We sum that up, and we get 3*5=15. So


Gives sum(repeat(5,3)), or 15.

To raise a number to the power another, things get a bit more complicated. However, squaring is relatively simple.



These two programs both square 5. The first does so by first repeating 5, 2 times. Putting 5 5 on the branch. Then, the next * repeats 5, 5 times. Putting 5, 5, 5, 5, 5 on the branch. Then, the + sums it.

Strings and Lists.

In TacO, a string is just a list of UTF-8 bytes. (There is no char construct). Constructing a list of numbers will make it implicitly print as a string of characters. For example.

  1 1 1 1 7
  1 0 0 0 2
  1 8 8 1

The above script places the numbers 72, 101, 108, 108 then 111 into a list via the l character. Which is then printed as the word Hello.

The more appropriate method to write this string however is:


Like most langauges, escape characters such as \n work, and like most 2d languages, the string is constructed in the last direction of the branch.

"Hello, World"

Is incorrect, and will result in the compile stage soft-crashing.



Is more correct. As is:

p"Hello, World!"

Although flat number lists are the most common type of list, a list can also hold other lists. Make of that what you will.

Conditionals, Looping, and Input

Conditionals are the simplest form of actual branching. The conditional character ? takes an input variable, and two branches. If the variable is truthy, use branch one, otherwise, use branch two.


The above code is a branching statement, if 1 is truthy, it will return "True", otherwise, it will return "False"

These have to be branches, that is,

  1 2 3

Won't return 2 if 1 is truthy and 3 otherwise, instead it wont return anything.

The i character gets input, and can optionally take a number argument to get the nth input. This is important, because in a loop, all the inputs are moved over by one.

Assume the number 3 is on the command line.


Will print that 3. If 3 and 2 are on the command lines, then they can be acessed with i or i1 and i2.

The looping construct is %. If this construct is passed a number on the first branch, it will loop through all numbers from 1 to n, running the second branch, passing that currently iterated number to the input. If it's passed a list, it will iterate through all the elements of the list, passing their elements.


The above code prints numbers 1-5. The 5 is the first branch of the looping construct, so it runs the second branch, which just contains i, 5 times, giving i numbers 1 - 5.

You can still access those lower inputs, as they were just pushed to the right. For example.


The above code loops through all numbers from 1-i, and adds i to them. For the input 3, the output is 4, 5, 6. The self referenced i by the second branch gets the current iteration, the i2 gets the initial input.

All the Functions

  • @: The IP start point. Only one per program, please.
  • +: Sums all the inputs, and returns as a single number/list.
  • *: Take a single number from the first branch. If there's a second branch, run that the first number times, otherwise, just return the second value on the first branch repeated the first value times.
  • 0-9: All numbers push themselves concatenated to the front of it's arguments. @1#2 pushes 12, for example.
  • <^>v: Branch restrictors, can only branch in the direction they point.
  • #: Intentional no-op. Does absolutely nothing.
  • p: Write all arguments (Separated by tabs) to STDOUT, followed by a newline.
  • w: Write all arguments, concatenated together, to STDOUT.
  • j: Concatenate a list or strings(lists) (second arguemnt), separated by the first argument.
  • i: Get the first argument numbered input, or the first if none is specified. In a loop, the iterator is first.
  • -: Subtract all the arguments, in order. Return the output.
  • n: Try to convert a list to a number.
  • s: Get a list representation of a number.
  • g: Get the value at index (second argument) of the list in the first argument.
  • ?: If the first return value of the first branch is truthy, execute the second one, else, optionally execute the third.
  • %: Take the first return value of the first branch. If it's a list, execute the second branch with each value of the list. If it's a number, execute the second branch with each number 1-n.
You can’t perform that action at this time.