Unfurl a string

27

3

Given a square string, produce all the output for the string at every stage of unfurling.

The string must unfurl in a clockwise direction one quarter turn at a time.

Examples

Input:

A

Output:

A

Note: I'll also accept the input duplicated for this particular test case only if this helps reduce your byte count.

Input:

DC
AB

Output:

DC
AB

  D
ABC

ABCD

Input:

GFE
HID
ABC

Output:

GFE
HID
ABC

   HG
   IF
ABCDE

     IH
ABCDEFG

       I
ABCDEFGH

ABCDEFGHI

Input:

JIHG
KPOF
LMNE
ABCD

Output:

JIHG
KPOF
LMNE
ABCD

    LKJ
    MPI
    NOH
ABCDEFG

       NML
       OPK
ABCDEFGHIJ

          ON
          PM
ABCDEFGHIJKL

            PO
ABCDEFGHIJKLMN

              P
ABCDEFGHIJKLMNO

ABCDEFGHIJKLMNOP

Rules

This is so the shortest code in bytes wins.

  • Any reasonable format can be used for I/O assuming it is consistent.
  • Spaces must be used to pad the top lines of the output.
  • Must be able to handle input of all printable characters (including space: \x20-\x7e):
 !"#$%&'()*+,-./0123456789:;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
  • Leading/trailing whitespace is allowed.
  • You can assume the string will always be a square.
  • All standard loopholes are forbidden.

Inspiration: Write a square program that outputs the number of times it has been “unrolled”.

Dom Hastings

Posted 2017-08-21T05:51:19.423

Reputation: 16 415

May we output ["A","A"] for "A", like my program does (instead of ["A"])? It seems reasonable to me since they're just the starting and the ending positions, and you only try to unfurl it once. – Mr. Xcoder – 2017-08-21T07:53:00.163

@Mr.Xcoder I agree, adding code to cater for that specific test case seems like a waste of bytes. I'll accept it for the single byte input and update the question accordingly! – Dom Hastings – 2017-08-21T08:15:59.873

3+1 from me, very interesting challenge. This site needs more of these, since they raise the difficulty level and gets rid of the triviality of most solutions. This goes straight to my favourite challenges list. I am disappointed that this has few answers though, I'd really like too see other clever approaches – Mr. Xcoder – 2017-08-21T11:49:44.530

@Mr.Xcoder I'm glad you like it! I wish I could take credit for coming up with the idea alone, but it's all thanks to @HelkaHomba's challenge!

– Dom Hastings – 2017-08-21T12:49:18.047

Answers

9

SOGL V0.12, 21 20 19 18 17 bytes

ø;[;ο⁴№č▓┼№TJι;jI

Try it Here! ( added because this expects input on the stack)

Explanation:

ø;[;ο⁴№č▓┼№TJι;jI
ø;               push an empty string below the input           stack with the input GFE,HID,ABC
  [              while [ToS (the array) isn't empty] do       ["", [["G","F","E"],["H","I","D"],["A","B","C"]]]  
                                                                stack at the second time looping
   ;               duplicate 2nd from top                     [[[H,G], [I,F], [D,E]], "ABC"]
    ο              wrap it in an array                        [[[H,G], [I,F], [D,E]], ["ABC"]]
     ⁴             duplicate 2nd from top                     [[[H,G], [I,F], [D,E]], ["ABC"], [[H,G], [I,F], [D,E]]]
      №            reverse vertically                         [[[H,G], [I,F], [D,E]], ["ABC"], [[D,E], [I,F], [H,G]]]
       č▓          join the inner arrays (┼ fails otherwise)  [[[H,G], [I,F], [D,E]], ["ABC"], ["DE", "IF", "HG"]]
         ┼         add the 2 parts together                   [[[H,G], [I,F], [D,E]], ["ABCDE", "   IF", "   HG"]]
          №        reverse vertically again                   [[[H,G], [I,F], [D,E]], ["   HG", "   IF", "ABCDE"]]
           T       print that without popping                 [[[H,G], [I,F], [D,E]], ["   HG", "   IF", "ABCDE"]]
            J      take the last line off                     [[[H,G], [I,F], [D,E]], ["   HG", "   IF"], "ABCDE"]
             ι     remove the rest of the array               [[[H,G], [I,F], [D,E]], "ABCDE"]
              ;j   remove the last line of the original array ["ABCDE", [[H,G], [I,F]]]
                I  rotate it clockwise                        ["ABCDE", [[I,H], [F,G]]]

dzaima

Posted 2017-08-21T05:51:19.423

Reputation: 19 048

7

Python 2, 209 207 205 203 202 201 200 196 bytes

-4 bytes thanks to @Quelklef!

s=input();l=len;k=''.join;exec"print s;s=[x for x in[' '*l(s[0])+k(x[:-1]for x in s[-2::-1])[t::l(s[0])-1]for t in range(l(s[0]))][:-1]+[s[-1]+k(x[-1]for x in s)[-2::-1]]if x.strip()];"*(2*l(s)-1)

Try it online!

Python 2, 219 217 215 213 212 211 207 bytes

s=input();l=len;k=''.join;exec"print'\\n'.join(s);s=[x for x in[' '*l(s[0])+k(x[:-1]for x in s[-2::-1])[t::l(s[0])-1]for t in range(l(s[0]))][:-1]+[s[-1]+k(x[-1]for x in s)[-2::-1]]if x.strip()];"*(2*l(s)-1)

Try it online!

The first one outputs as a list of Strings, the second one outputs as ASCII-art.

Mr. Xcoder

Posted 2017-08-21T05:51:19.423

Reputation: 39 774

I think [::-1][1:] can be [-2::-1], like in Lynn's answer. – Quelklef – 2017-08-23T21:38:44.450

@Quelklef Thanks a lot! – Mr. Xcoder – 2017-08-23T21:40:38.513

4

Charcoal, 42 35 bytes

AEθSθW⊟θ«⪫θ¶AEι⮌⪫Eθ§μλωθ⊞υι↙←⮌⪫υωD⎚

Try it online! Link is to verbose version of code. Edit: Saved 7 bytes mostly by switching from character arrays to strings. Explanation:

AEθSθ

Read the input square as an array of strings into the variable q.

W⊟θ«

While the last string in the array is not empty, remove it.

⪫θ¶

Print the rest of the array.

AEι⮌⪫Eθ§μλωθ

Rotate the rest of the array by looping through each character of the last string and joining the lth character of every remaining string in the reversed array.

⊞υι↙←⮌⪫υω

Append the previously removed last string to u, which holds the unfurled value, and print it.

D⎚

Output the result and then clear the canvas ready for the next iteration.

Note that this version outputs the final unfurl on a separate line, if this is undesirable then for 38 bytes:

AEθSθW⊟θ«⊞υι←E⁺⟦⪫υω⟧⮌θ⮌κAEι⮌⪫Eθ§μλωθD⎚

Try it online! Link is to verbose version of code. Explanation: ←E⁺⟦⪫υω⟧⮌θ⮌κ reverses the current array, prepends the unfurled line, then reverses the characters in each line, then prints everything upside-down, thus producing the desired result.

Neil

Posted 2017-08-21T05:51:19.423

Reputation: 95 035

I tried doing it a more Charcoal-y way but I couldn't work out where the Rotate and Trim commands leave the cursor... – Neil – 2017-08-21T15:50:05.230

3

Haskell, 127 120 bytes

e=[]:e
i#[x]=[]
i#s|t<-foldl(flip$zipWith(:))e$init s,j<-i++last s=(map((j>>" ")++)(init t)++[j++last t]):j#t
f s=s:""#s

Try it online!

Input is a list of lines, e.g. ["DC","AB"] for the second test case, output is a list of lists of lines: [["DC","AB"],[" D","ABC"],["ABCD"]]. Use mapM (putStrLn . unlines) to pretty-print the result.

Edit: Saved 7 bytes by noticing that the shorter transpose I found some while a go comes in handy because it can be modified to reverse each transposed directly.

Laikoni

Posted 2017-08-21T05:51:19.423

Reputation: 23 676

2

05AB1E, 18 bytes

[Dí.Bí»,¤UR¦ζŽ`Xì)

Try it online!

Explanation

[            Ž       # while stack is not empty, do:
 D                   # duplicate current list
  í                  # reverse each element
   .B                # pad with spaces to equal length
     í               # reverse each element again
      »,             # join with newlines and print
        ¤U           # store the last element in X
          R¦         # reverse the list and remove the first element
            ζ        # zip with spaces as filler
              `      # split elements separately to stack
               Xì    # prepend X to the last element
                 )   # join the stack to a list

Emigna

Posted 2017-08-21T05:51:19.423

Reputation: 50 798

2

J, 62 bytes

|."1@([:(#~[:-.[:*/"1' '=])|.@{:(}:@],{:@],[)|:@}:)^:(1<#)^:a:

Try it online!

I'm sure this can be golfed a lot. This prints extra whitespace, but only because of the way that J formats the arrays contained within the outputted array to have the same shape.

I think once I go in and comment out exactly what I'm doing, I might get a better idea of how to golf this (having done that now, I don't really know...). For purposes of golfing, it's worth noting that

  • I have to special case 1 row inputs (the while part of the loop)
  • I have to eliminate all lines consisting solely of whitespace (surely there must either be a builtin for this or a better way to do it), which is the filter near the end
  • There are a lot of caps, identity functions, and atops

Explanation

In ungolfing this, I'll be splitting the main function in three.

unfurl_reversed   =. |.@{: (}:@] , {:@] , [) |:@}:
whitespace_filter =. #~ [: -. [: */"1 ' ' = ]
unfurl            =. |."1@(whitespace_filter @: unfurl_reversed) ^: (1 < #) ^: a:

test_case         =. 3 3 $ 'GFEHIDABC'

We'll be working with the second test case.

unfurl_reversed

|.@{: (}:@] , {:@] , [) |:@}:

This gives one the string unfurled once, but in reverse. All of this is being done in reverse and in a specific order so that the way J automatically pads strings with spaces to match the shape of the array they're in will give the right spacing.

|:@}: is the transpose of the curtail of the input

   |:@}: test_case
GH
FI
ED

|.@{: is the reverse of the tail of the input

   |.@{: test_case
CBA

I think you can see what we want to do: we want to append the reverse of the tail to the last part of the transpose of the curtail (that's a mouthful, but basically attach CBA to the end of ED). This will give us one step of unfurling, reversed.

(}:@],{:@],[) does just that.

It appends CBA to ED, then joins that with the rest of the array. Our output therefore is

   unfurl_reversed test_case
GH   
FI   
EDCBA

whitespace_filter

#~ [: -. [: */"1 ' ' = ]
                 ' ' = ]  Equate each element to space
            */"1          Product of each row (all true?)
      -.                  Negate
#~                        Filter rows that are true

Basically, this tests to see if any row is completely spaces, and removes it if it is. It doesn't do anything for the first iteration of the test case.

This is necessary (at least until I find an alternative) since otherwise we'll eventually be unfurling whitespace into our output string.

unfurl

|."1@(whitespace_filter @: unfurl_reversed) ^: (1 < #) ^: a:

Unfurl basically puts the other functions together and special cases single character inputs.

When the power of verb (^:) is given the empty box (a:), it applies a function on an input until it converges and collects the results in an array.

(1 < #) checks that the rows are always greater than 1 (to special case 1 row inputs).

|."1 reverses each row, so it inverts the results of whitespace_filter @: unfurl.

cole

Posted 2017-08-21T05:51:19.423

Reputation: 3 526

1

Perl 5, 155 bytes

$"=$,;@a=map[/./g],<>;while(@a){say' 'x(length$s)."@$_"for@a[0..@a-2];say$s.="@{pop@a}";say@b=();for$i(0..$#a){$q=0;$b[$q++][$#a-$i]=$_ for@{$a[$i]}}@a=@b}

Try it online!

Saved a few bytes without really modifying the logic. The flow below is still basically correct.

# Perl 5, 163 bytes

$"=$,;@a=map[/./g],<>;while(@a){say' 'x(length$s)."@{$a[$_]}"for 0..@a-2;say$s.="@{pop@a}";say@b=();for$i(0..$#a){$b[$_][$#a-$i]=$a[$i][$_]for 0..$#{$a[$i]}}@a=@b}

Try it online!

How?

$"=$,; #set the array output separator to null
@a=map[/./g],<>;   # take the input as a 2-D array @a
while(@a){         # repeat while there are still things to unfurl
  say' 'x(length$s)."@{$a[$_]}"for 0..@a-2; # output all but last
                                            # line of the remaining
                                            # square
  say$s.="@{pop@a}";  # remove bottom row, add it to the unfurled string $s
                      # and output it
  say@b=();           # clear temporary array; output empty array, causing
                      # a newline to output

                      # rotate remaining shape 90 degrees:
  for$i(0..$#a){$b[$_][$#a-$i]=$a[$i][$_]for 0..$#{$a[$i]}}
  @a=@b               # replace input with rotated array
}

Xcali

Posted 2017-08-21T05:51:19.423

Reputation: 7 671

Nice method, but I'm after the output at each stage of unfurling, could you update to print all steps? Sorry! – Dom Hastings – 2017-08-21T15:23:30.453

1OK, I rewrote it. – Xcali – 2017-08-21T19:05:07.653

Perfect, thanks! Sorry for causing extra bytes though... – Dom Hastings – 2017-08-21T19:09:59.477

1

Python 2, 143 132 bytes

a=input()
while 1:print'\n'.join(a);b=map(''.join,zip(*map(str.strip,a[-2::-1])));a[-1]+=b.pop();a[:-1]=[len(a[0])*' '+x for x in b]

Try it online!

In each iteration, b is the “head” of the string (first n−1 rows), rotated 90 degrees: if a is [" NML", " OPK", "ABCDEFGHIJ"] then b is ["ON", "PM", "KL"].

To unfurl a string once, we append the final line of b to a[-1] (giving "ABCDEFGHIJKL") and then recompute a[:-1] by adding spaces to the rest of the strings in b.

We terminate by attempting to pop from b when it’s empty.

Python 2, 132 bytes

a=input()
while 1:s=str.strip;print'\n'.join(a);a[:-1]=[len(a[0])*' '+''.join(x)for x in zip(*map(s,a[-2::-1]))];a[-1]+=s(a.pop(-2))

Try it online!

Same idea, written differently. We terminate by attempting to a.pop(-2) when a has only one element.

Lynn

Posted 2017-08-21T05:51:19.423

Reputation: 55 648