Square-unspiral the string!

12

Given a string, first square it as follows:

First, write the string.

abcde

Next, write the string rotated one left.

abcde
bcdea

Keep doing this until you have written len(string) lines.

abcde
bcdea
cdeab
deabc
eabcd

Now, read from the string like this:

----+
+--+|
|+>||
|+-+|
+---+

Which gives:

abcdeabcdcbaedcbcdeabaede

Print this string.

Test cases

abcdef -> abcdefabcdedcbafedcbcdefabcbafedefaf
cena! -> cena!cenanec!anena!cec!a!
ppcg -> ppcgppcppgcpcgpg
abc -> abcabacbc
ab -> abab
a -> a
 -> 

Please comment if a test case is incorrect.

Remember, this is , so the code with the smallest number of bytes wins.

Oliver Ni

Posted 2016-11-03T04:59:59.857

Reputation: 9 650

2cena! is wrong. It should match your example with abcde since both are 5 letters: cena!cenanec!anena!cec!a! – Linus – 2016-11-03T13:33:57.413

@Linus Thank you, I have fixed it. – Oliver Ni – 2016-11-03T17:25:10.610

Answers

7

JavaScript (ES7), 83 80 78 77 bytes

s=>s.repeat(l=s.length).replace(/./g,_=>s[(c-=--i**.5-l&1||-1)%l],c=-1,i=l*l)

Bonus ES3-compliant program:

for(s=prompt(r=""),c=-1,l=s.length,i=l*l;i;)r+=s[(c-=l-Math.sqrt(i--)&1||-1)%l];alert(r)

Explanation

This takes advantage of the fact that the output for e.g. a length 5 string can be represented as:

abcdeabcd cbaedcb cdeab aed e
012345678 7654321 23456 543 4

where each digit represents an index in the string (starting at 0), modulo the length of the string. In other words, if n is the length of the string, we increment the index 2n - 1 times, then decrement it 2(n - 1) - 1 times, then increment it 2(n - 2) - 1 times, etc. This can be simplified to the following algorithm:

  • Start the index i at -1.
  • For each integer x in the range [n2..1]:
    • If floor(sqrt(x)) is of the same parity (even/odd) as n, increment i.
    • Otherwise, decrement i.
    • Add the character at index i mod n to the output.

This works because floor(sqrt(x)) switches parities after 2n - 1 iterations, then 2(n - 1) - 1 iterations, etc.

ETHproductions

Posted 2016-11-03T04:59:59.857

Reputation: 47 880

Rediculous. Good Job! – MayorMonty – 2016-11-04T03:35:54.977

1

Python 2.7 (in CMD.EXE), 91 bytes

This requires a terminal with a working backspace(\b), and will not work on repl.it or ideone.com. A print statement ending in a comma separates further output with space instead of a newline or return. The backspace allows us to overwrite the separating space.

s=input();r=s[::-1];n=len(s)-1;i=0
while i<=n:print'\b'+s[i:]+s[:n-i]+r[i+2:]+r[:n-i],;i+=2

Python 2.7, 96 bytes

Try it on ideone.com or repl.it (thanks to Oliver). Input must be a python string, e.g.'cena!'.

s=input();r=s[::-1];n=len(s)-1;i=0;S=''
while i<=n:S+=s[i:]+s[:n-i]+r[i+2:]+r[:n-i];i+=2
print S

The four slices appended by the loop (s[i:],s[:n-i],r[i+2:],r[:n-i]) are taken from four edges of the spiral. For instance with 01234 the square is:

01234
12340
23401
34012
40123

So we take 01234,0123,210,4321. The variable i is the index of the top-left value in each step of the process. In the final spiral several of the slices may be empty.

Linus

Posted 2016-11-03T04:59:59.857

Reputation: 1 948

It's probably not the only save, but by changing to Python 3, getting rid of the S='', print S, and S+=, and wrapping everything before the i+=2 in a print() statement with sep='', you can save 2 bytes. – Kade – 2016-11-03T16:58:04.653

@Shebang I'm not following right off. Feel free to add a python 3 answer yourself. – Linus – 2016-11-03T17:03:47.850

You can change i<=n to n>i – Oliver Ni – 2016-11-04T17:46:08.007

It saves a byte. – Oliver Ni – 2016-11-04T18:45:36.773

@Oliver, Thanks... but it does not work for "a string of odd length." – Linus – 2016-11-04T18:59:44.850

@Oliver No, it would be n>=i, since the equality case must be kept. – Erik the Outgolfer – 2016-11-04T20:49:37.783

1

Pyth, 15 bytes

.Wp.(H0_CZ.<LQU

A program that takes input of a "quoted string" and prints the result.

Try it online! or verify all test cases (modified for multiple input).

How it works

.Wp.(H0_CZ.<LQU  Program. Input: Q
            L U  Map over [0, 1, 2, 3, ..., Q-1] (implicit input):
          .< Q     Q left-shifted by that many characters
                 Call this X
.W               While
   .(H0          popping the first element of X (mutates X in-place)
  p              and printing it with no trailing newline is truthy:
         Z           X = 
        C            X transposed
       _             reversed

TheBikingViking

Posted 2016-11-03T04:59:59.857

Reputation: 3 674

1

Jelly, 11 10 bytes

ẋ2µṖȮṖUµÐL

TryItOnline!, or all tests

How?

The unspiralled square is a series of "top-edge plus right-edge" and "bottom-edge plus left-edge" runs, each of which is the reverse of the previous run without the first and last letter, and the first of which is the input plus the input without the last letter (e.g. input "abcde" has an output of "abcdeabcd" + "cbaedcb" + "cdeab" + "aed" + "e").

ẋ2µṖȮṖUµÐL - Main link: s                            e.g. abcde
ẋ2         - repeat s twice                          e.g. abcdeabcde
  µ    µ   - monadic chain separation
        ÐL - repeat until results are no longer unique:
   Ṗ       -     remove the last character                abcdeabcd / cbaedcb / cdeab / aed / e   / ""
    Ȯ      -     print z (with no linefeed) and return z
     Ṗ     -     remove the last character                abcdeabc  / cbaedc  / cdea  / ae  / ""  / ""
      U    -     reverse                                  cbaedcba  / cdeabc  / aedc  / ea  / ""  / "" <- no longer unique.

Jonathan Allan

Posted 2016-11-03T04:59:59.857

Reputation: 67 804

1

05AB1E, 12 bytes

2×[DõQ#¨D?¨R

Try it online!

Explanation:

 2×[DõQ#¨D?¨R
               # Implicit input
 2×            # Repeat twice
   [           # Begin infinite loop
┏>  DõQ#       # If empty string, break
┃       ¨      # Remove last character
┃        D     # Duplicate
┃         ?    # Print with no newline and pop
┃          ¨   # Remove last character
┃           R  # Reverse
┗━━━━━━━━━━━━┛ # Implicit end infinite loop

Oliver Ni

Posted 2016-11-03T04:59:59.857

Reputation: 9 650

0

MATL, 27 bytes

"GX@q_YS]vGn1YL_GnoQ&Ple&S)

The empty input exits with an error (producing the correct output).

Try it online! Or verify all test cases.

Luis Mendo

Posted 2016-11-03T04:59:59.857

Reputation: 87 464

0

C, 95 94 Bytes

i,j,k,l;f(char*s){for(k=-1,l=i=strlen(s);i--;)for(j=i*2;~j--;putchar(s[(k+=(l-i)%2*2-1)%l]));}

Inspired by @ETHproductions answer.

cleblanc

Posted 2016-11-03T04:59:59.857

Reputation: 3 360

0

Perl, 99 bytes

$_=<>;
chop;
@a=split//;
print(@a[$%,(@f=1-($b=@a-$%)..$b-3),$b-1?$b-2:(),reverse@f]),$%+=2 until$%>@a

Whitespace is not part of the program and is provided for readability.

Not extremely efficient code. I should be able to shorten the first three lines somehow, but everything I tried to do failed. That ternary operator also needs to be fixed somehow, but having it this way made it possible to shorten my code by like, 10 bytes because I could cut out so much.

The code works by compiling a list of palindromes, separated by even numbers, which represent the place values of the string to be pulled.

Gabriel Benamy

Posted 2016-11-03T04:59:59.857

Reputation: 2 827

You can use -F which will replace line 1 and 3. Give the input with echo -n to remove the chop. (that should get you around 81 bytes) – Dada – 2016-11-04T22:42:16.607

0

Actually, 21 13 bytes

This algorithm is largely based on Jonathan Allan's Jelly answer. There are two ways to go about printing the result as one string. The approach used here duplicates an intermediate step and then adds it to a running total in register 1 (an empty string by default); ;╕ in the function, then at the end. The other approach is to duplicate an intermediate step, leave those duplicate steps on the stack, and sum them into one string at the end; ; in the function, then at the end.

Golfing suggestions welcome. Try it online!

2*`dX;╕dXR`Y╛

Ungolfing

         Implicit input s.
2*       Push a string that repeats s two times.
`...`Y   Call the following function until there is no change from the last call
  dX       Discard the last element. Call this new string m.
  ;╕       Duplicate m and add it to the running total in register 1.
  dXR      Discard the last element again and reverse the string.
╛        Push the unspiralled string from register 1 to the stack.
         Implicit return.

Sherlock9

Posted 2016-11-03T04:59:59.857

Reputation: 11 664

0

Python 3, 59 bytes

x=input()*2
while x:x=x[:-1];print(x,end='');x=x[:-1][::-1]

repl.it

A direct port of my Jelly answer; only a full program taking input (rather than a function).
The print(x,end='') is a print statement which will not print the default newline.

Jonathan Allan

Posted 2016-11-03T04:59:59.857

Reputation: 67 804

-1

Python 3, 93 bytes

s=input();r,n,i=s[::-1],len(s)-1,0
while n-i:print(s[i:]+s[:n-i]+r[i+2:]+r[:n-i],end='');i+=2

Try it online!

Oliver Ni

Posted 2016-11-03T04:59:59.857

Reputation: 9 650

Rather than print(...,end=''), do print(end=s[i:]+s[:n-i]+r[i+2:]+r[:n-i] – FlipTack – 2016-11-04T19:05:13.097

1Anyway, this solution doesn't work for abcde, it's missing an e at the end. – FlipTack – 2016-11-04T19:06:41.903

Try i<=n instead of n-i for your condition. – Linus – 2016-11-04T19:09:38.330