Thanks to Sp3000 for some help while golfing this.
<""-}:?:?
"`
{
++(!@
Try it online!
Explanation
It turns out that the 2*min(a,b)-1
approach isn't the shortest in Labyrinth. Instead it's easier to compute (a+b)-|a-b|-1
.
Labyrinth primer:
- Labyrinth has two stacks of arbitrary-precision integers, main and aux(iliary), which are initially filled with an (implicit) infinite amount of zeros. I will usually represent these like
Main [... a b | c d ...] Aux
, where Main
grows to the right, Aux
grows to the left and ...
represents the implicit zeros at the bottom.
- The source code resembles a maze, where the instruction pointer (IP) follows corridors when it can (even around corners). The code starts at the first valid character in reading order, i.e. in the top left corner in this case. When the IP comes to any form of junction (i.e. several adjacent cells in addition to the one it came from), it will pick a direction based on the top of the main stack. The basic rules are: turn left when negative, keep going ahead when zero, turn right when positive. And when one of these is not possible because there's a wall, then the IP will take the opposite direction. The IP also turns around when hitting dead ends.
- The source code can be modified at runtime using
<>^v
which cyclically shift a row or column of the grid.
The code starts on the <
which immediately modifies the source code. This is a common golfing trick in Labyrinth whenever a program starts with a long-ish bit of linear code. Afterwards, the source looks like this, with the IP still on the <
:
""-}:?:?<
"`
{
++(!@
Since the IP is now in a dead end, it has to start moving left. The linear code does the following:
Op Explanation Stacks
? Read integer a from STDIN. Main [... a | ...] Aux
: Duplicate. Main [... a a | ...] Aux
? Read integer b from STDIN. Main [... a a b | ...] Aux
: Duplicate. Main [... a a b b | ...] Aux
} Move b over to aux. Main [... a a b | b ...] Aux
- Subtract b from a on main. Main [... a (a-b) | b ...] Aux
The code now enters the only nonlinear part of the code which compues -abs(x)
, (where I'm now using <
and v
to indicate entry and exit points):
""<
"`
v
The "
is a no-op (i.e. it does nothing), whereas the `
multiplies the top of the main stack by -1
. Let's go through the three possible cases of control flow:
- If
a == b
, i.e. a-b
is zero, the IP keeps moving west on the first "
. Then it hits a corner on the the second "
and has to turn south. Again, it keeps moving south on the third "
and leaves this 2x2 block. All in all, nothing happens to zeros at all.
- If
a > b
, i.e. a-b
is positive, the IP turns south on the first "
. The `
then switches the top of the main stack to b-a
and the IP has to take a turn west. On the next "
the top of the stack is now negative, and the IP turns south. Therefore, if the top of the stack is positive, its sign will be negated by this block.
- If
a < b
, i.e. a-b
is negative, then the IP also turns towards the `
, which now makes it positive. That means the IP turns north on the next no-op. It hits the corner and turns east, and turns south once more so that it reaches the `
a second time. At this point, the control flow is no different from a positive input, so after applying `
twice, we're back at a-b
which is negative and leaves the loop. Despite doing a lot more stuff, negative inputs are also unaffected by this part of the code.
Now that we've computed -abs(a-b)
, the remainder of the code is all linear again:
Op Explanation Stacks
[... a -|a-b| | b ...]
{ Move b back to main. [... a -|a-b| b | ...]
+ Add. [... a (-|a-b|+b) | ...]
+ Add. [... (a+b-|a-b|) | ...]
( Decrement. [... (a+b-|a-b|-1) | ...]
! Print as integer. [... | ...]
@ Terminate program.
I like your wording. – Bálint – 2016-05-01T12:43:04.400
1Also, is a full program needed or just a function? It makes a big difference in java. Even in javascript. – Bálint – 2016-05-01T12:46:39.123
2
@Bálint There are default rules for this.
– Martin Ender – 2016-05-01T13:16:17.113For a=1 and b=2, why can't I have two triangles, 1,1,2 and 1,2,2? – Neil – 2016-05-01T13:52:24.613
@Neil 1,1,2 is flat. – Leaky Nun – 2016-05-01T13:53:07.970
So it is. Never mind me. – Neil – 2016-05-01T13:54:48.647