15
\$\begingroup\$

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.
  • If possible, please add a link with a test for your code.
  • Also, add an explanation for your answer if you think it is needed.
\$\endgroup\$
11
  • 3
    \$\begingroup\$ Closely related \$\endgroup\$
    – Giuseppe
    Apr 5, 2019 at 12:59
  • 2
    \$\begingroup\$ Also this one: codegolf.stackexchange.com/questions/125966/…, but none include the termination check. \$\endgroup\$
    – Bromind
    Apr 5, 2019 at 13:03
  • 3
    \$\begingroup\$ Suggested test case: ProgrammingPuzzlesAndCodeGolf - the final tail length greater than 1 tripped me up. \$\endgroup\$
    – Sok
    Apr 5, 2019 at 13:48
  • 1
    \$\begingroup\$ 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 [...]". \$\endgroup\$ Apr 5, 2019 at 21:08
  • 1
    \$\begingroup\$ Downvoted because of overly restrictive input/output rules; I deleted my Python 2 answer since one cannot use print inside a lambda. \$\endgroup\$
    – Chas Brown
    Apr 8, 2019 at 3:48

9 Answers 9

7
\$\begingroup\$

Charcoal, 15 bytes

FS«F¬℅§KV⁰⟲⁶→Pι

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

FS«

Loop over the carpet.

F¬℅§KV⁰

Check whether there's anything above the cursor.

⟲⁶

If not then roll the carpet.

→Pι

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.

\$\endgroup\$
2
  • \$\begingroup\$ That's awesome. So basically Charcoal has a builtin "roll" operator in ? \$\endgroup\$
    – Jonah
    Apr 6, 2019 at 14:27
  • 1
    \$\begingroup\$ @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. \$\endgroup\$
    – Neil
    Apr 6, 2019 at 16:52
3
\$\begingroup\$

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
\$\endgroup\$
3
\$\begingroup\$

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.
\$\endgroup\$
2
\$\begingroup\$

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 , ]

\$\endgroup\$
5
  • \$\begingroup\$ Ah, J... letters are for noobs \$\endgroup\$
    – RK.
    Apr 6, 2019 at 16:43
  • \$\begingroup\$ ,. can do what 1 1$] does and $ can be used as {.. \$\endgroup\$
    – FrownyFrog
    Apr 6, 2019 at 16:55
  • \$\begingroup\$ @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? \$\endgroup\$
    – Jonah
    Apr 6, 2019 at 17:07
  • 1
    \$\begingroup\$ The last line of the explanation, you use {. to truncate, that one can be a $ as far as I understand. \$\endgroup\$
    – FrownyFrog
    Apr 7, 2019 at 10:15
  • \$\begingroup\$ Also you can replace the right [: with a @ \$\endgroup\$
    – FrownyFrog
    Apr 7, 2019 at 10:17
1
\$\begingroup\$

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
}
\$\endgroup\$
1
\$\begingroup\$

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:
   ð               ð           -   the enclosed dyadic chain -- i.e. f(head, tail):
    Z                          -     transpose
     U                         -     reverse each (giving a rotated head)
              ɗ                -     last three links as a dyad:
          ¥                    -       last two links as a dyad:
       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)
                  ¤            -     nilad followed by link(s) as a nilad:
                ®              -       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)
                             Ɗ - last three links as a monad:
                          Ḣ    -   pop and yield head
                           Y   -   join with newline characters
                            ;  -   concatenate (the remaining tail)
                               - when running as a full program implicitly prints
\$\endgroup\$
1
\$\begingroup\$

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.

\$\endgroup\$
0
\$\begingroup\$

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!

\$\endgroup\$
2
  • 1
    \$\begingroup\$ need to print it \$\endgroup\$
    – ASCII-only
    Apr 8, 2019 at 0:41
  • \$\begingroup\$ @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. \$\endgroup\$
    – PieCot
    Apr 13, 2019 at 10:18
0
\$\begingroup\$

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!

\$\endgroup\$
6
  • 1
    \$\begingroup\$ sadly, op says you have to print \$\endgroup\$
    – ASCII-only
    Apr 8, 2019 at 0:41
  • \$\begingroup\$ @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. \$\endgroup\$
    – PieCot
    Apr 13, 2019 at 10:33
  • \$\begingroup\$ might wanna make that clearer then \$\endgroup\$
    – ASCII-only
    Apr 14, 2019 at 1:00
  • \$\begingroup\$ @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... \$\endgroup\$
    – PieCot
    Apr 14, 2019 at 10:46
  • 1
    \$\begingroup\$ 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 \$\endgroup\$
    – ASCII-only
    Apr 14, 2019 at 11:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.