13
Stack Cats is a reversible, stack-based language. Its reversible nature makes for somewhat weird loops. This challenge is about the conditional loop (...)
. When these loops are nested in certain ways, it's possible to transform the code to reduce the nesting depth. Here are the rules (where A
and B
stand for an arbitrary snippets):
- When one loop starts with another loop, we can extract the inner loop to the front:
((A)B)
becomes(A)(B)
. - When one loop ends with another loop, we can extract the inner loop to the end:
(B(A))
becomes(B)(A)
. - Empty loops,
()
, can be removed from the program entirely. As a corollary (in conjunction with the other rules),((A))
is equivalent to(A)
.
The only nested loops that will remain are of the form (A(B)C)
, where A
, B
and C
are non-empty.
The Challenge
You're given a valid Stack Cats program and your task is to reduce the nesting level of loops as much as possible, leaving no empty loops, using the above transformations.
A valid Stack Cats program...
- ... consists only of the characters
()/\<>[]{}!"*+-:=ITX^_|
. - ... has mirror symmetry (e.g.
\(]{}!{}[)/
is a valid program, but/|/
isn't). - ... has correctly matched and nested
()
and{}
([]
,<>
and\/
don't necessarily need to be matched as usual, although they'll appear in pairs due to the mirror symmetry requirement).
You can take either a string or a list of characters as input, but output needs to be presented in the same format.
You may write a program or a function and use any of our standard methods of receiving input and providing output. Note that these loopholes are forbidden by default.
This is code-golf, so the shortest valid answer – measured in bytes – wins.
Test Cases
Test cases are two lines each (input and output), separated by empty lines. Note that one output is empty. You also need to support the empty input (which should result in empty output).
(((=+|+=)))
(=+|+=)
({(=+|+=)})
({(=+|+=)})
((\)/)I(\(/))
(\)(/)I(\)(/)
(()()(())()())
((<|>((X((T)))[_]))\^/(([_](((T))X))<|>))
(<|>)(X)(T)([_])(\^/)([_])(T)(X)(<|>)
Just to be sure, loops we have to extract are only indicated by parenthesis
()
, so an input{{A}B}
will remain as is and won't be extracted to{A}{B}
as well? – Kevin Cruijssen – 2018-02-20T09:19:21.177@KevinCruijssen Yes, the transformation is only valid for
(...)
-type loops. – Martin Ender – 2018-02-20T09:25:31.417In the final test case, why is
\^/
inside parenthesis? – Kevin Cruijssen – 2018-02-20T11:24:31.7031@KevinCruijssen Those are the outermost parentheses after you extract
(<|>((X((T)))[_]))
and(([_](((T))X))<|>)
. – Martin Ender – 2018-02-20T11:26:32.7071Ah I see. So
((A)B(C))
will become(A)(B)(C)
due to both rules 1 and 2 subsequently:((A)B(C))
→(A)(B(C))
(rule 1) →(A)(B)(C)
(rule 2). – Kevin Cruijssen – 2018-02-20T11:30:15.513@KevinCruijssen Exactly. – Martin Ender – 2018-02-20T11:30:56.130
Is this possible in Stack Cats? I’ve got a thing for meta-programming – Stan Strum – 2018-02-25T21:09:13.907
@StanStrum Stack Cats is Turing-complete, so knock yourself out. ;) (But it's not exactly easy to program in, so I'd be absolutely floored if anyone actually manages to solve this in Stack Cats.) – Martin Ender – 2018-02-25T21:30:37.383
Note that it's possible to convert from C (8cc) to BF, and from BF to SKS, but doing that would be considered a non serious contender. – user202729 – 2018-02-26T09:47:59.810