Sub-100! This was a fun one.
Explanation
Let's start with a brief primer on Labyrinth – feel free to skip this if you're already familiar with the basics:
Labyrinth has two stacks – a main stack and an auxiliary stack. Both stacks have an infinite number of zeroes at the bottom, e.g.
+on an empty stack adds two zeroes, thus pushing zero.Control flow in Labyrinth is decided by junctions, which look at the top of the stack to determine where to go next. Negative means turn left, zero means go straight ahead and positive means turn right... but if we hit a wall then we reverse direction. For example, if only straight ahead and turn left are possible but the top of the stack is positive, then since we can't turn right we turn left instead.
Digits in Labyrinth pop
xand push10*x + <digit>, which makes it easy to build up large numbers. However, this means that we need an instruction to push 0 in order to start a new number, which is_in Labyrinth.
Now let's get to the actual code!
Red
Execution starts from the " in the top- I'll post an explanationleft corner, which is a NOP. Next is ), which increments the top of the stack, pushing 1 on the first pass and incrementing n on every following pass.
Next we duplicate n with :. Since n is positive, we turn right, executing } (shift top of main stack to auxiliary) and :. We hit a dead end, so we turn around and execute } and : once I'm done golfingmore, leaving the stacks like
Main [ n n | n n ] Aux
Once again, n is positive and we turn right, executing _101/ which divides n by 101. If n is 101 then n/101 = 1 and we turn into the @, which terminates the program. Otherwise, our current situation is
Main [ n 0 | n n ] Aux
Orange 1 (mod 3)
3 turns the top zero into a 3 (10*0 + 3 = 3) and % performs a modulo. If n%3 is positive, we turn right into the yellow ". Otherwise we perform 70.105.122:.., which outputs Fizz. Note that we don't need to push new zeroes with _ since n%3 was zero in this case, so we can exploit the infinite zeroes at the bottom of the stack. Both paths meet up again at light blue.
Light blue
The top of the stack is currently n%3, which could be positive, so the _; just pushes a zero and immediately pops it to make sure we go straight ahead, instead of turning into the @. We then use = to swap the tops of the main and auxiliary stacks, giving:
Main [ n | n%3 n ] Aux
Orange 2 (mod 5)
This is a similar situation to before, except that 66.117.122:.. outputs Buzz if n%5 is zero.
Dark blue
The previous section leaves the stacks like
Main [ n%5 | n%3 n ] Aux
{ shifts the n%3 back to the main stack and * multiplies the two modulos.
If either modulo is zero, the product is zero so we go straight into yellow. = swaps the top of the stacks and _ pushes a zero to make sure we go straight ahead, giving
Main [ n 0 | 0 ] Aux
Otherwise, if both modulos are nonzero, then the product is nonzero and we turn right into green. = swaps the tops of the stacks, giving
Main [ n | (n%5)*(n%3) ] Aux
after which we use : to duplicate n, turn right, then use ! to output n.
Purple
At this point, the main stack has either one or two items, depending on which path was taken. We need to get rid of the zero from the yellow path, and to do that we use +, which performs n + 0 in some order for both cases. Finally, \ outputs a newline and we're back at the start.
Each iteration pushes an extra (n%5)*(n%3) to the auxiliary stack, but otherwise we do the same thing all over again.
Sub-100! This was a fun one - I'll post an explanation once I'm done golfing.
Sub-100! This was a fun one.
Explanation
Let's start with a brief primer on Labyrinth – feel free to skip this if you're already familiar with the basics:
Labyrinth has two stacks – a main stack and an auxiliary stack. Both stacks have an infinite number of zeroes at the bottom, e.g.
+on an empty stack adds two zeroes, thus pushing zero.Control flow in Labyrinth is decided by junctions, which look at the top of the stack to determine where to go next. Negative means turn left, zero means go straight ahead and positive means turn right... but if we hit a wall then we reverse direction. For example, if only straight ahead and turn left are possible but the top of the stack is positive, then since we can't turn right we turn left instead.
Digits in Labyrinth pop
xand push10*x + <digit>, which makes it easy to build up large numbers. However, this means that we need an instruction to push 0 in order to start a new number, which is_in Labyrinth.
Now let's get to the actual code!
Red
Execution starts from the " in the top-left corner, which is a NOP. Next is ), which increments the top of the stack, pushing 1 on the first pass and incrementing n on every following pass.
Next we duplicate n with :. Since n is positive, we turn right, executing } (shift top of main stack to auxiliary) and :. We hit a dead end, so we turn around and execute } and : once more, leaving the stacks like
Main [ n n | n n ] Aux
Once again, n is positive and we turn right, executing _101/ which divides n by 101. If n is 101 then n/101 = 1 and we turn into the @, which terminates the program. Otherwise, our current situation is
Main [ n 0 | n n ] Aux
Orange 1 (mod 3)
3 turns the top zero into a 3 (10*0 + 3 = 3) and % performs a modulo. If n%3 is positive, we turn right into the yellow ". Otherwise we perform 70.105.122:.., which outputs Fizz. Note that we don't need to push new zeroes with _ since n%3 was zero in this case, so we can exploit the infinite zeroes at the bottom of the stack. Both paths meet up again at light blue.
Light blue
The top of the stack is currently n%3, which could be positive, so the _; just pushes a zero and immediately pops it to make sure we go straight ahead, instead of turning into the @. We then use = to swap the tops of the main and auxiliary stacks, giving:
Main [ n | n%3 n ] Aux
Orange 2 (mod 5)
This is a similar situation to before, except that 66.117.122:.. outputs Buzz if n%5 is zero.
Dark blue
The previous section leaves the stacks like
Main [ n%5 | n%3 n ] Aux
{ shifts the n%3 back to the main stack and * multiplies the two modulos.
If either modulo is zero, the product is zero so we go straight into yellow. = swaps the top of the stacks and _ pushes a zero to make sure we go straight ahead, giving
Main [ n 0 | 0 ] Aux
Otherwise, if both modulos are nonzero, then the product is nonzero and we turn right into green. = swaps the tops of the stacks, giving
Main [ n | (n%5)*(n%3) ] Aux
after which we use : to duplicate n, turn right, then use ! to output n.
Purple
At this point, the main stack has either one or two items, depending on which path was taken. We need to get rid of the zero from the yellow path, and to do that we use +, which performs n + 0 in some order for both cases. Finally, \ outputs a newline and we're back at the start.
Each iteration pushes an extra (n%5)*(n%3) to the auxiliary stack, but otherwise we do the same thing all over again.