<
,,}:?
.
;(" {(={}{".
,",;=};} }) "{@
Input is N
followed by the string, separated by any non-numeric character.
Try it online!
This was written in collaboration with Sp3000 (which means I couldn't be bothered to figure out an algorithm, so he started working on it, came up with 118 byte solution but couldn't be bothered golfing it, so I did the golfing... yay for teamwork).
Explanation
Sp's usual primer (as usual slightly modified):
- Labyrinth is a stack-based 2D language with two stacks, main and auxiliary. Pretty much everything happens on the main stack, but you can shift values over to the other one, e.g. to reverse them or save them for later.
- The stacks are bottomless and filled with zeroes, so popping from an empty stack is not an error.
- Execution starts from the first valid character (here the top left). At each junction, where there are two or more possible paths for the instruction pointer (IP) to take, the top of the stack is checked to determine where to go next. Negative is turn left, zero is go forward and positive is turn right. While this was meant to make the code look like winding, twisty passages, there's nothing stopping you from making "rooms" where these conditions are checked in every cell. Those can yield quite unpredictable behaviour, but are great for golfing.
- The source code (and therefore the layout of the labyrinth) can be modified at runtime using
<>^v
which cyclically shifts a row or column or the grid.
"
are no-ops.
Here we go.
The code starts on the <
, which is a golfing trick I've used a few times when starting with a long piece of linear code. It shifts the first row cyclically to the left, with the IP on it, so the source then looks like this:
<
,,}:?
.
;(" {(={}{".
,",;=};} }) "{@
But now the IP can't move anywhere, so it executes the <
again. This continues until we reach this state:
<
,,}:?
.
;(" {(={}{".
,",;=};} }) "{@
At this point, the IP can leave the cell and begin executing the second line starting from the ?
. So here's the linear code broken down:
? # Read the first integer on STDIN, i.e. N.
:} # Duplicate it and move one copy over to the auxiliary stack.
, # Read the separator character.
,. # Read the first character of the input string and directly print it.
The IP now enters this 3x2 room, which is actually two tightly-compressed (overlapping) 2x2 clockwise loops. The first loop reads and discards N-1
characters from STDIN.
; # Discard the top of the stack. On the first iteration, this is the
# separator we've already read. On subsequent iterations this will be
# one of the N-1 characters from the input string.
( # Decrement N. If this hits zero, we leave the loop, otherwise we continue.
, # Read the next character from STDIN to be discarded.
Now we enter the second loop which reads the remainder of the input string. We can detect EOF because ,
will return -1
in that case, making the IP turn left.
, # Read a character. Exit the loop if EOF.
( # Decrement it.
That decrement isn't actually useful, but we can undo it later for free and here it allows us to overlap the two loops.
If we take the 5 ABCDEFGHIJKLMNOP
input as an example, the stack looks like this:
Main [ ... 'E' 'F' 'G' 'H' 'I' 'J' 'K' 'L' 'M' 'N' 'O' -1 | 5 ... ] Auxiliary
Note that these actually correspond to the input characters FGHIJKLMNOP
(because we decremented them), and that we don't actually want to print the first of those (we've only discarded N-1
characters, but want to skip N
).
Now there's a short linear bit that prepares the stack for the next loop:
; # Discard the -1.
= # Swap the tops of the stacks, i.e. N with the last character.
# By putting the last character on the auxiliary stack, we ensure that
# it doesn't get discarded in the next loop.
} # Move N over to the auxiliary stack as well.
The stacks now look like:
Main [ ... 'E' 'F' 'G' 'H' 'I' 'J' 'K' 'L' 'M' 'N' | 5 'O' ... ] Auxiliary
We enter another 2x2 clockwise loop. This discards the top N
characters from the main stack:
; # Discard the top of the main stack.
{ # Pull N over from the auxiliary stack.
( # Decrement it. It it's 0 we leave the loop.
} # Push N back to the auxiliary stack.
When we exit the loop =
swaps that 0
and the last character of the input string again. Now the stacks look like this:
Main [ ... 'E' 'F' 'G' 'H' 'I' 'O' | ... ] Auxiliary
We want to print the contents of the main stack (except the bottom element and all incremented by 1), from the left. That means we need to get it over to the auxiliary stack. That's what the next 2x2 (clockwise) loop does:
{ # Pull an element over from the auxiliary stack. This is necessary so we
# have a 0 on top of the stack when entering the loop, to prevent the IP
# from turning right immediately.
} # Move the top of the main stack back to the auxiliary stack. If this was the
# bottom of the stack, exit the loop.
) # Increment the current character.
} # Move it over to the auxiliary stack.
Stacks now:
Main [ ... | 'F' 'G' 'H' 'I' 'J' 'P] ... ] Auxiliary
We move the first of those (the one we don't want to print) back to the main stack with {
. And now we enter final 2x2 (counterclockwise) loop, which prints the rest:
{ # Pull another character over from the auxiliary stack. Exit the loop
# if that's the zero at the bottom of the stack.
. # Print the character.
Finally we terminate the program with @
.
'
as the counting character? For example:''123321
? \$\endgroup\$N
, but can it be a string, with quotes? I mean, forN=3
take'111'
(as opposed to111
) \$\endgroup\$