Introduction
><>
is a 2D language, meaning programs are executed as a pointer moving around the codespace. The pointer starts in the top left moving right, and each individual character is its own instruction that manipulates either the pointer's direction/position, or the data that is stored on the stack or the actual codespace.
Some more golfing tips can be found at https://codegolf.stackexchange.com/questions/47035/tips-for-golfing-in-fish
Instructions
You can find a list of instructions at https://esolangs.org/wiki/Fish, though it is pretty intuitive once you start getting into it. As a quick reference though (y will refer to the top of the stack, x as second):
- Movement:
<^>v
(directions), /\|_#
(mirrors), .
(jump to (x,y) then move), ?
(skip next if non-zero), !
(skip)
- Stack manipulation:
$
(swap), @
(rotate top three), :
(duplicate), ~
(pop), r
everse, {}
(rotate stack left/right), &
(store in/push from register)
- Values:
0-9a-f
(0 to 15), l
(push length of stack), "'
(start string)
- Operators:
+-*,%
(,
is division) =()
(comparison: x=y, x<y, x>y)
- I/O:
i
nput, o
utput, n
umeric output
- Misc:
g
et value from (x,y), p
ut a value into (x,y), [
(move y values to new stack), ]
(pop stack, dump values on old stack), ;
(halt)
Pushing values
><>
only has one datatype, rationals, so when you push a string, you are actually pushing a series of codepoints. If you want to push a large number, e.g. 1000, you can use the character at that codepoint ("Ϩ"
). Some characters visually affect the code (such as RTL characters), but don't worry, they'll still work (just use a placeholder until then).
Combine strings
With the above tip, you might end up with multiple sets of ""
in your code. If you can, try to push all the values at once and then manipulate the stack differently to use them later.
Loops
Single line loop
The pointer is physically moving around the codespace, so you actually have to construct loops physically. The easiest loop is to use the wrapping behaviour of the codespace as a one line loop. For example, io
just takes a character of input and outputs it again repeatedly.
If you need to initialise the loop with a value, you can do skip the first instruction on every subsequent loop by appending a !
at the end.
0:nao1+!
Mirror loops
If you want to chain loops together, a good format to use is:
..?\
..?\
Adding on extra lines as necessary. If the first line is longer than the second, try swapping them and shift the mirrors to the start.
/...?
/........?
Jump loops
You can also use .
to jump places, most commonly in conjunction with conditions as one coordinate or as both coordinates. You can also use it to skip lengthy initialisation sections.
Use l
This one's very important. A lot of holes require some sort of counter, either as something to filter, and/or to manipulate some persistent value. Instead of starting with 0
and incrementing this every loop, you can instead use the l
ength of the stack and push some arbitrary value each loop. This can be combined with your initialisation process, usually by starting your program with something like 1}
or l<
. For example, our incrementing program in the loop section can be:
lnao0}
If you find yourself doing changing the value by small amounts afterwards, see if you can move the l
to a different spot with the correct stack height e.g. 0l1-
=> l0$
, or l1+nao
=> alno
.
Termination
On code.golf, you can either terminate a program properly with ;
, or you can terminate with an error.
Divison/modulo by zero
This can often be used in place of ?;
, where you invert the condition and divide the top of the stack by either 1 or 0, e.g. "e"l)?;
=> "d"l(,
. If you already use a division or modulo in your normal code, you may be able to manipulate the divisor/modulus to be zero when you want to terminate.
Invalid instruction
Characters that aren't instructions will throw an error when the pointer hits them. You can use this either by p
utting a character in the middle of your normal code, directing your pointer into what is meant to be your data section.
Empty stack
There weren't enough elements on the stack to do whatever it was you were attempting. You can use this to terminate by e.g. pushing all the values/input first, then loop assuming the stack is full.
Invalid use of [
The interpreter will error if you try and create a stack with an invalid number of elements (either negative or more than your current stack). This differs from the original interpreter, which only errored on the negative part.
Outputting a negative number
The most common way of doing this is to output the value of EOF (-1).
General tips
- Reduce whitespace. This should be your number one priority, besides simplifying logic to remove instructions themselves. Remove those nasty spaces and keep it on as few lines as you can.
- You can sometimes use
}{
in place of the register &
if you want to store multiple values. You might even be able to just r
everse the stack at the end of the loop to start again
- Reuse instructions. You can often change around the pointer paths to intersect with other parts of the program, or even with the data itself.
[]
may seem rather useless in general programming, but they do have their advantages. ]
will clear a stack if there's nothing on the stack-stack, you can manipulate sections of the stack e.g. 5[r]
to reverse the top 5 values, and each stack stack has its own register value.
- Invert conditions to turn
?!
to to just ?
- The interpreter code.golf uses is written by @primo-ppcg (thanks!), and uses rationals as the number representation. This means that constant holes aren't insanely annoying, phew. You will still need to output it properly though, either by
- Multiplying the number by 10^1000 and flooring it (
:1%-
). You can make this value at the same time as you're generating the number, usually by iterating some X000 times and multiplying a value by 10 every X loops.
- Alternatively, countdown from 1000 after generating the number, printing each digit by multiplying by ten, outputting (with
'0'+o
or :1%-n
), then moduloing by one.