:-:_
Try it online! In the footer I've included all other 4-byte solutions. (Stack Cats ignores everything after the first linefeed.)
Try the reverse!
Explanation
The -n
flag turns on numeric output (and input, but we don't have any), and the -m
flag is normally just a golfing convenience which lets you avoid the redundant part of the source code. This is because every Stack Cats program needs to have mirror symmetry. With the -m
flag you only give it the first half (plus the central character). So the actual program here is:
:-:_:-:
As you can see in the first TIO link, there's a ton of 4-byte solutions, but I picked this one for its simplicity. Stack Cats is stack-based, and this program only uses the initial stack. Since we don't have any input, it contains a single -1
(an EOF marker) on top of an infinite well of zeros. The three commands in the program have the following meaning:
: Swap the top two stack elements.
- Negate the top stack element (i.e. multiply by -1).
_ Pop a. Peek b. Push b-a.
So here is how the program modifies the stack (states and commands are staggered to indicate how each command changes the stack from one state to the next):
: - : _ : - :
-1 0 0 -1 1 0 0 1
0 -1 -1 0 0 1 1 0
0 0 0 0 0 0 0 0
… … … … … … … …
As it turns out, the only command that really does anything here is _
which turns our EOF marker into a 1
. Output at the end of the program is implicit, and the EOF marker is optional, so this just prints out the 1
we get.
Now if we reverse the source code, due to the implicit mirroring, the actual program becomes:
_:-:-:_
This does something very different:
_ : - : - : _
-1 1 0 0 1 -1 0 -1
0 0 1 1 0 0 -1 -1
0 0 0 0 0 0 0 0
… … … … … … … …
This time the bottom of the stack is still a -1
so it does act as the EOF marker and only the -1
on top of it gets printed.
...
Now with all of that said, since Stack Cats has such a unique relationship with reversing code, I feel that using -m
is a little cheating. It's normally only meant to save bytes by omitting the redundant part of the source code, but here it actually makes the challenge a lot easier and even the full program shorter. This is because reversing a full program will only change the program if it contains any of <>[]
, which also means that the program ends up making use of multiple stacks (Stack Cats actually has a tape of stacks, where all but the initial one are only filled with zeros to begin with). Furthermore, reversing it then just swaps the <>
and []
pairs, which still makes the execution symmetric. The only way to break that symmetry is to use I
which does -]
or -[
or nothing depending on the sign of the top of the stack. So...
*|]I*:*I[|*
Try it online! The footer again includes all other alternatives at the same byte count. Some of those output 1/-1 and some output 2/-2 as indicated after each program. I picked this one to explain kinda randomly as one of the ones that output 2.
Try the reverse!
Explanation
As I said, this one's a bit longer. Even if we did use the -m
notation for this, it would weigh in at 6 bytes instead of the above 4.
The commands in use this time:
* Toggle the least significant bit of the top of the stack.
| Reverse the longest non-zero of prefix on this stack.
[] Move one stack to the left/right and take the top of the current stack with you.
I If the top of the stack is positive, -], if it's negative, -[, otherwise do nothing.
: Swap the top two stack elements.
The first program only uses two stacks. That's a bit messy to do in ASCII art, but I'll try my best. The square brackets indicate which stack the tape head is on, and I'll put the commands between each pair of stack states.
[-1]
… 0 0 …
0 0
… …
*
[-2]
… 0 0 …
0 0
… …
| (does nothing)
]
[-2]
… 0 0 …
0 0
… …
I
[2]
… 0 0 …
0 0
… …
*
[3]
… 0 0 …
0 0
… …
:
[0]
… 3 0 …
0 0
… …
*
[1]
… 3 0 …
0 0
… …
I
[-1]
… 3 0 …
0 0
… …
[
[-1]
… 3 0 …
0 0
… …
|
[ 3]
… -1 0 …
0 0
… …
*
[ 2]
… -1 0 …
0 0
… …
Now the -1
acts as an EOF marker and the 2
gets printed.
The other program is the same until the [
. It's still virtually the same all the way until the second I
. We'll technically be on a different stack, but without values on them, they're all indistinguishable. But then the difference between I[
and I]
ends up mattering:
*|[I*:*I
[-1]
… 3 0 0 …
0 0 0
… … …
]
[-1]
… 3 0 0 …
0 0 0
… … …
| (does nothing)
*
[-2]
… 3 0 0 …
0 0 0
… … …
And this time, we don't have an EOF marker, but the program still outputs the -2
.
-
(0x45 = 0b00101101) works in Jelly --
yields -1 since it defines the literal -1, whileṆ
(0xB4 = 0b10110100) yields 1 since it performs a logical not of the implicit input of zero. (Of courseṆ
works just as well :p) \$\endgroup\$