# Roll the carpet

This question is inspired by Kevin Cruijssen's question.

Now that the carpet is laid out, we want to roll it. Your task is to write a program that takes a string and returns a spiral made from this string (representing a rolled carpet viewed from the side).

The procedure for one step of rolling the carpet is the following. There is an example to illustrate what I mean. Notice that the example starts with a partially rolled carpet for better understanding:

ac
rpet

• separate the "head" from the "tail" of the carpet: the head is what has been rolled so far, the tail is what remains to be rolled.
Head: ac   Tail:
rp          et

• Rotate the head 90°, clockwise.
Rotated head: ra   Tail (unchanged):
pc                       et

• if the width of the new head (here 2) is less or equal than the length of the tail (here 2)
• then, put it on top of the tail
• else, the carpet (as it was at the begining of the step) was rolled
New carpet: ra
pc
et


Repeat the procedure as many times as needed.

Two examples showing all steps of the carpet rolling:

carpet

c
arpet

ac
rpet

ra
pc
et

0123456789

0
123456789

10
23456789

21
30
456789

432
501
6789


## Some precisions:

• You don't need to show all intermediate steps, only the rolled carpet (e.g. if you find a non-iterative way to compute the result, it's perfect). Also, you don't need to print any leading whitespace, in the examples above, I only show them to align stuff.
• Input is a String, a list/array of char
• Output is printed to stdout or to a file.
• Input is nice: the length is at least 1 char, and at most a constant sufficiently small so that it doesn't cause problems, but you can't use that constant in your program; the content of the string is only nice characters ([a-zA-Z0-9]), encoding at your preference.
• This is , so shortest answer in bytes wins. Don't let code-golf languages discourage you from posting answers with non-codegolfing languages. Try to come up with an as short as possible answer for 'any' programming language.
• Default Loopholes are forbidden.
• Closely related – Giuseppe Apr 5 at 12:59
• Also this one: codegolf.stackexchange.com/questions/125966/…, but none include the termination check. – Bromind Apr 5 at 13:03
• Suggested test case: ProgrammingPuzzlesAndCodeGolf - the final tail length greater than 1 tripped me up. – Sok Apr 5 at 13:48
• I think you've swapped the words "head" and "tail" here: "if the width of the new head [...] is greater or equal than the length of the tail [...]". – Erik the Outgolfer Apr 5 at 21:08
• Downvoted because of overly restrictive input/output rules; I deleted my Python 2 answer since one cannot use print inside a lambda. – Chas Brown Apr 8 at 3:48

# Charcoal, 15 bytes

ＦＳ«Ｆ¬℅§ＫＶ⁰⟲⁶→Ｐι


Try it online! Link is to verbose version of code. Explanation:

ＦＳ«


Loop over the carpet.

Ｆ¬℅§ＫＶ⁰


Check whether there's anything above the cursor.

⟲⁶


If not then roll the carpet.

→Ｐι


Move right and output the current character.

Example: For the input 0123456789, the following actions occur:

0


0 is printed.

01


The cursor moves right and 1 is printed.

0
1


Since there is nothing above the 1, the canvas is rotated.

0
12


The cursor moves right and the 2 is printed.

10
2


Since there is nothing above the 2, the canvas is rotated.

10
23


The cursor moves right and the 3 is printed.

10
234


The cursor moves right and the 4 is printed.

21
30
4


Since there is nothing above the 4, the canvas is rotated.

21
30
45


The cursor moves right and the 5 is printed.

21
30
456


The cursor moves right and the 6 is printed.

432
501
6


Since there is nothing above the 6, the canvas is rotated.

432
501
67


The cursor moves right and the 7 is printed.

432
501
678


The cursor moves right and the 8 is printed.

432
501
6789


The cursor moves right and the 9 is printed.

• That's awesome. So basically Charcoal has a builtin "roll" operator in ⟲? – Jonah Apr 6 at 14:27
• @Jonah Well, it won't roll for me as it goes, but by outputting the string character-by-character I can roll as I go, yes. – Neil Apr 6 at 16:52

# Pyth, 37 bytes

.U+j;bZ.WgleHJlhH,+_MChZ<eZJ>eZJ,]hQt


Try it online here, or verify all the test cases at once here.

.U+j;bZ.WgleHJlhH,+_MChZ<eZJ>eZJ,]hQtQ   Implicit: Q=eval(input())
Trailing Q inferred
]hQ     First character of Q, wrapped in an array
tQ   All but the first character of Q
,        2-element array of the two previous results
This yields array with rolled carpet (as array of strings) followed by the tail
.W                                While condition function is truthy, execute inner function, with initial value of the above:
gleHJlhH                          Condition function, input H
JlhH                            Number of layers in the current rolled carpet, store in J
leH                                Lenth of the tail
g   J                               Is the above greater than or equal to J?
,+_MChZ<eZJ>eZJ           Inner function, input Z
_MChZ                     Rotate the current rolled carpet (transpose, then reverse each row)
+     <eZJ                 Append the first J characters of the tail as a new row
,                           Pair the above with...
>eZJ             ... all but the first J characters of the tail - this is the new tail
.U+j;bZ                                  Join the carpet roll on newlines and append the tail, implicit print


# Husk, 24 bytes

►S=ÖLmFȯ:T↔ø§z:oΘḣĠ+CṘ2N


Try it online!

## Explanation

Implicit input, say s="carpets"

CṘ2N  Break s into chunks:
N   Natural numbers: [1,2,3,4,..
Ṙ2    Repeat each twice: [1,1,2,2,3,3,4,4,..
C      Break s into chunks of these lengths: ["c","a","rp","et","s"]
The last chunk is shorter if we run out of characters.

§z:oΘḣĠ+  Attempt to merge suffix of chunks:
Ġ    Cumulative reduce chunk list from right
+   by concatenation: ["carpets","arpets","rpets","ets","s"]
oΘḣ     Prefixes of chunk list (empty and nonempty): [[],["c"],..,["c","a","rp","et","s"]]
§z         Zip these by
:        appending: [["carpets"],["c","arpets"],..,["c","a","rp","et","s"]]
These are all versions of the chunk list where some suffix has been merged.

mFȯ:T↔ø  Roll each list:
m         Map
F        reduce from left
ø   starting from empty character matrix
ȯ:T↔    by this function:
T↔     Reverse and transpose (rotating by 90 degrees)
ȯ:       then append next chunk as new row.
Result: [["carpets"],["c","arpets"],..,["epr","tca","s"]]

►S=ÖL  Select the matrix rolled by the correct amount:
►       Find element that maximizes
S=     being equal to
ÖL   sort by length.
This selects a matrix whose rows have non-decreasing lengths.
Ties are broken by choosing the rightmost one.
Result: ["ra","pc","ets"]

Implicitly print each row separated by newlines.


# J, 69 bytes

-3 bytes thanks to FrownyFrog

[:(}:@[,{:@[,])&>/[:((|:@|.@[,#@[$]);#@[}.])&>/^:(<:&#&>/)^:_,.@{.;}.  Try it online! ## explanation [: (}:@[ , {:@[ , ])&>/ [: ((|:@|.@[ , #@[ {. ]) ; #@[ }. ])&>/^:(<:&#&>/)^:_ }. ;~ 1 1$ {.


The algorithm is straightforward despite being a bit verbose for J.

Overall Strategy: Reduce the input to a square table, with a (possibly empty) leftover piece.

As we reduce, we'll use a 2 element list of boxes. Our "result so far" will be the first box, and "items remaining to be processed" will be the 2nd box. The first box will be initialized to the head of the input (but converted to a table):

1 1 ${.  and "items remaining to be processed" will be the input's tail: }. ;~  Now we have: ┌─┬─────┐ │c│arpet│ └─┴─────┘  where the 'c' is actually a 1x1 table. We reduce that down using a J Do... While loop: ^:(...)^:_  Where the part in parenthesis is the "keep going" condition: <:&#&>/  which says "keep going while the length of the right box is greater than or equal to the length of the left box (ie, the side length of the square matrix) What does "keep going" mean? That's defined in the verb to the left of the first ^:, which tells us how to take the current result and produce the next iteration. That verb is: ((|:@|.@[ , #@[ {. ]) ; #@[ }. ])&>/  Let's break it down: ((|:@|.@[ , #@[ {. ]) ; #@[ }. ])&>/ ( verb in parens )&>/ NB. put the verb in parens NB. between the two items NB. of our list, and unbox NB. them into left / right NB. args ([ / ]) for the verb (|:@|.@[ , #@[ {. ]) ; #@[ }. ] NB. breaking down verb in NB. parens... ; .... NB. new "remaining items": }. ] NB. remove from remaining #@[ NB. the size of a side of NB. the result matrix .... ; NB. new "result": |:@|.@[ NB. rotate existing result , NB. and put it on top of #@[ {. ] NB. the items we removed NB. from remaining items  That is, this is just algorithm described in the OP translated literally into J. Finally we deal with the (possibly 0) leftover items, the tail of our carpet roll: (}:@[ , {:@[ , ])&>/  This says "take all but the last elm of the result": }:@[  and append it to , the last items of the result {:@[ with the remaining items appended to that last item , ] • Ah, J... letters are for noobs – RK. Apr 6 at 16:43 • ,. can do what 1 1$] does and $ can be used as {.. – FrownyFrog Apr 6 at 16:55 • @FrownyFrog ty. I got it to 70 bytes with your first suggestion but wasn't sure if I understood $ can be used as {. -- can you clarify? – Jonah Apr 6 at 17:07
• The last line of the explanation, you use {. to truncate, that one can be a $as far as I understand. – FrownyFrog Apr 7 at 10:15 • Also you can replace the right [: with a @ – FrownyFrog Apr 7 at 10:17 # R, 146 132 bytes function(s){m=F[F] while({m=rbind(t(m)[,F:0],s[1:F]) s=s[-1:-F] length(s)>sum(F<-dim(m))})0 write(m[F:1,],1,F[1],,"") cat(s,sep="")}  Try it online! Implements the carpet-rolling procedure. Takes input as a list of characters and prints to stdout. Saved 14 bytes by finding a way to use a do-while loop and initializing using F. function(s){ m=F[F] # logical(0); create an empty array (this gets automatically promoted to character(0) later while( # do-while loop {m=rbind(t(m)[,F:0],s[1:F]) # rotate m counterclockwise and add the first F characters of s to the bottom s=s[-1:-F] # remove those characters length(s)>sum(F<-dim(m))})0 # while the number of characters remaining is greater than the sum of m's dimensions write(m[F:1,],1,F[1],,"") # write the rolled portion write writes down the columns, we reverse each column cat(s,sep="") # and write the remaining characters }  # Jelly, 30 bytes Seems overly long... ḢW,ðZU;Ls@¥©ḢWɗ,®Ẏ¤ð/ẈṢƑ$¿ḢY;Ɗ


Try it online!

### How?

ḢW,ðZU;Ls@¥©ḢWɗ,®Ẏ¤ð/ẈṢƑ$¿ḢY;Ɗ - Main Link: list of characters Ḣ - pop and yield head W - wrap in a list , - pair with (the remaining list after Ḣ) ¿ - while...$      - ...condition: last two links as a monad:
Ẉ         -   length of each
Ƒ       -   is invariant under:
Ṣ        -     sort
/          - ...do: reduce by:
Z                          -     transpose
U                         -     reverse each (giving a rotated head)
L                       -         length (i.e. number of rows in current roll)
@                     -         with swapped arguments:
s                      -           split (the tail) into chunks of that length
©                   -       (copy to register for later)
Ḣ                  -       pop and yield head (Note register "copy" is altered too)
W                 -       wrap in a list
;                        -     concatenate (the rotated head with the first chunk of the tail)
®              -       recall from register (other chunks of tail, or an empty list)
Ẏ             -       tighten (the chunks to a flat list)
,               -     pair (the concatenate result with the tightened chunks)
Ḣ    -   pop and yield head
Y   -   join with newline characters
;  -   concatenate (the remaining tail)
- when running as a full program implicitly prints


# 05AB1E, 41 bytes

g©L¦€DD2šηO®>‹Ï©IŽ8OS®g4α._.ΛðÜI®O®g->.$«  Way too long, but I wanted to use the Canvas.. Which was probably a bad choice now that I've finished it and it turned out to be this long.. Try it online. (No test suite, because there seems to be a weird issue with the .Λ builtin..) Explanation: Let me start by giving a general explanation of the Canvas and what I wanted my code to accomplish. More detailed information can be found in this relevant 05AB1E tip of mine, but for this challenge I wanted to have do the following: The Canvas builtin takes three parameters: • $$\a\$$: The size(s) of the line(s). For this challenge, this would be a list [2,2,3,3,4,4,5,5,...]. • $$\b\$$: The character(s) we want to display. For this challenge, this would simply be the input-string. • $$\c\$$: The direction in which we want to draw these character-lines. For this challenge this would be the directions $$\[2,0,6,4]\$$ ($$\[→,↑,←,↓]\$$) rotated $$\n\$$ amount of times depending on the input-string to have a different starting direction (i.e. input carpet is $$\[0,6,4,2]\$$ instead and input 0123456789ABCDEFGHI is $$\[6,4,2,0]\$$ instead). As for the code: g # Get the length of the (implicit) input-string © # Store it in the register (without popping) L # Create a list in the range [1,length] ¦ # Remove the first item to make the range [2,length] €D # Duplicate each to get the list [2,2,3,3,4,4,5,5,...] D2š # Create a copy and prepend a 2: [2,2,2,3,3,4,4,5,5,...] η # Get the prefixes: [[2],[2,2],[2,2,2],[2,2,2,3],...] O # Sum each prefix: [2,4,6,9,12,16,20,...] ® # Push the length from the register again >‹ # Check for each summed prefix if it's <= length Ï # And only leave the truthy values © # And store this in the register (without popping) # (This is our a for the Canvas builtin) I # Push the input-string # (This is our b for the Canvas builtin) Ž8O # Push compressed integer 2064 S # Converted to a list of digits: [2,0,6,4] ®g # Push the list from the register, and get its length 4α # Get the absolute difference with 4 ._ # And rotate the [2,0,6,4] that many times towards the left # (This is our c for the Canvas builtin) .Λ # Now use the Canvas builtin, without printing it yet ðÜ # Remove any trailing spaces (since the Canvas implicitly makes a rectangle) ®O # Push the sum of the list from the register ®g- # Subtract the length of the list from the register > # And add 1 I .$    # Remove that many leading characters from the input-string
«   # And append it at the end of the roll created by the Canvas
# (after which the result is output implicitly)


See this 05AB1E tip of mine (section How to compress large integers?) to understand why Ž8O is 2064.

# Python 3, 112 bytes

r=lambda t,h=[[]]:len(h)>len(t)and h[:-1]+[h[-1]+list(t)]or r(t[len(h):],list(zip(*h[::-1]))+[list(t)[:len(h)]])


In this case, the output is the value of the function.

Try it online!

If you prefer, here another (longer, 129 bytes) solution that prints directly the rolled input:

r=lambda t,h=['']:len(h)>len(t)and set(map(print,h[:-1]+[h[-1]+t]))or r(t[len(h):],list(map(''.join,zip(*h[::-1])))+[t[:len(h)]])


Try it online!

• need to print it – ASCII-only Apr 8 at 0:41
• @ASCII-only: Quoting the author of the question: "If returning instead of printing shows a great improvment or a nice trick, post an answer (and explicit that you are returning, not printing)". So I think it's okay. – PieCot Apr 13 at 10:18

# MATLAB / Octave, 154 bytes

Not the shortest one, but to golf in MATLAB/Octave is always fun :)

function h=r(t,h);n=fliplr(h');s=size(n,2);q=numel(t);if s<=q h=r(t(max(s,1)+1:end),[n; t(1:max(s,1))]);elseif q>0 h(:,end+q)=' ';h(end,end-q+1:end)=t;end


Try it online!

• sadly, op says you have to print – ASCII-only Apr 8 at 0:41
• @ASCII-only as explained here (it.mathworks.com/matlabcentral/answers/…), stdout in Matlab world refers to the command window. Given that the result of the evaluation of every command is automatically printed to the command window, I think that this answer could be considered consistent with the requirements of the question. – PieCot Apr 13 at 10:33
• might wanna make that clearer then – ASCII-only Apr 14 at 1:00
• @ASCII-only I do not get what do you mean, really. It is a function, you call it, the result will be automatically printed on the command window (i.e. stdout). What's wrong with this? Even the R answer works like this... – PieCot Apr 14 at 10:46
• Right now you disp it, I'd say you should remove the disp to let people that don't know R that it does write to STDOUT by default – ASCII-only Apr 14 at 11:36